<?php

namespace App\Http\Controllers\APIS\CustomerApi;

use App\Http\Controllers\Controller;
use App\Models\Asset;
use App\Models\Customer;
use App\Models\Device;
use App\Models\DeviceProfileMaster;
use App\Models\TimeseriesAlertMessage;
use App\Models\TimeseriesKeyMaster;
use App\Models\User;
use App\Models\UserAssetLink;
use App\Services\AdminService;
use App\Services\AlarmService;
use App\Services\CustomerInfoService;
use App\Services\TelemetryService;
use Exception;
use Illuminate\Container\Attributes\DB;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB as FacadesDB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;

class TelemetryController extends Controller
{
    protected $customerInfoService, $alarmService, $adminService, $telemetryService;

    // public function __construct(CustomerInfoService $customerInfoService)
    // {
    //     $this->customerInfoService = $customerInfoService;
    // }
    public function __construct(CustomerInfoService $customerInfoService, AlarmService $alarmService, AdminService $adminService, TelemetryService $telemetryService)
    {
        $this->customerInfoService = $customerInfoService;
        $this->alarmService = $alarmService;
        $this->adminService = $adminService;
        $this->telemetryService = $telemetryService;
    }



    // public function telemetryDataAsset(Request $request)
    // {
    //     try {
    //         $token = readHeaderToken();
    //         $userId = $token['sub'];
    //         $customerId = User::where('id', $userId)->value('customer_id');

    //         // Validate request
    //         $validator = Validator::make($request->all(), [
    //             'asset_id' => 'required|string',
    //         ]);

    //         if ($validator->fails()) {
    //             return jsonResponseWithErrorMessage($validator->errors()->first(), 400);
    //         }

    //         $assetId = $request->input('asset_id');

    //         // Verify asset ownership
    //         $assetLinkExists = UserAssetLink::where('user_id', $userId)
    //             ->where('asset_id', $assetId)
    //             ->exists();

    //         if (!$assetLinkExists) {
    //             return response()->json([
    //                 'error' => 'You are not authorized to access this asset',
    //                 'code' => 'UNAUTHORIZED_ACCESS'
    //             ], 403);
    //         }

    //         // Set timestamps in milliseconds for database query
    //         $endTsMs = now()->timestamp * 1000; // Current time in milliseconds
    //         $startTsMs = $endTsMs - (30 * 60 * 1000); // 30 minutes ago in milliseconds

    //         // Get devices with their telemetry keys
    //         $devices = Device::with([
    //             'deviceProfile' => function($query) {
    //                 $query->select(['id', 'name']); // Only select needed fields
    //             },
    //             'timeseriesKeys' => function ($query) {
    //                 $query->where('display_on_dashboard', true)
    //                     ->orWhere('display_on_popup', true)
    //                     ->select(['id', 'device_profile_xid', 'key_name', 'display_name', 'display_on_dashboard', 'display_on_popup']);
    //             }
    //         ])->where('asset_id', $assetId)
    //           ->where('customer_id', $customerId)
    //           ->get();

    //         if ($devices->isEmpty()) {
    //             return response()->json([
    //                 'error' => 'No devices found for the specified asset',
    //                 'code' => 'DEVICES_NOT_FOUND'
    //             ], 404);
    //         }

    //         // Process telemetry data for each device
    //         $response = $devices->map(function ($device) use ($startTsMs, $endTsMs) {
    //             $keysData = $device->timeseriesKeys;
    //             $keyNames = $keysData->pluck('key_name')->toArray();

    //             // Get telemetry data for start and end times
    //             $startTelemetry = $this->customerInfoService->getTelemetryData($device, $keyNames, $startTsMs, $startTsMs);
    //             $endTelemetry = $this->customerInfoService->getTelemetryData($device, $keyNames, $endTsMs, $endTsMs);

    //             $alarmMap = $this->getDeviceAlarmsForTelemetry($device->id);
    //             $alertMessages = TimeseriesAlertMessage::whereIn('timeseries_key_master_xid', $keysData->pluck('id'))
    //                 ->orderBy('min_value', 'asc')
    //                 ->get()
    //                 ->groupBy('timeseries_key_master_xid');

    //             $telemetry = $keysData->map(function ($keyData) use ($startTelemetry, $endTelemetry, $alarmMap, $alertMessages) {
    //                 $startData = collect($startTelemetry[$keyData->key_name] ?? [])->last();
    //                 $endData = collect($endTelemetry[$keyData->key_name] ?? [])->last();

    //                 $startValue = floatval($startData['value'] ?? 0);
    //                 $endValue = floatval($endData['value'] ?? 0);

    //                 // Determine trend
    //                 $trend = null;
    //                 if ($startValue > 0) {
    //                     if ($endValue > $startValue) {
    //                         $trend = 'upward';
    //                     } elseif ($endValue < $startValue) {
    //                         $trend = 'downward';
    //                     } else {
    //                         $trend = 'stable';
    //                     }
    //                 }

    //                 // Format timestamp
    //                 $currentData = $endData ?? $startData ?? ['ts' => now()->timestamp * 1000];
    //                 $timestamp = is_float($currentData['ts']) || $currentData['ts'] > 9999999999
    //                     ? intval($currentData['ts'] / 1000)
    //                     : $currentData['ts'];

    //                 // Color code logic
    //                 $colorCode = null;
    //                 if ($endValue == 0) {
    //                     $colorCode = "grey";
    //                 } elseif (isset($alertMessages[$keyData->id])) {
    //                     foreach ($alertMessages[$keyData->id] as $alertMsg) {
    //                         if ((is_null($alertMsg->min_value) || $endValue >= floatval($alertMsg->min_value)) &&
    //                             (is_null($alertMsg->max_value) || $endValue <= floatval($alertMsg->max_value))) {
    //                             $colorCode = $alertMsg->color_code;
    //                             break;
    //                         }
    //                     }
    //                 }

    //                 return [
    //                     'key_name'             => $keyData->key_name,
    //                     'display_name'         => $keyData->display_name,
    //                     'display_on_dashboard' => $keyData->display_on_dashboard,
    //                     'display_on_popup'     => $keyData->display_on_popup,
    //                     'timestamp'            => $timestamp,
    //                     'value'                => $endValue,
    //                     'start_value'          => $startValue > 0 ? $startValue : null,
    //                     'trend'                => $trend,
    //                     'alert'                => isset($alarmMap[$keyData->key_name]),
    //                     'color_code'           => $colorCode ?: 'green', // Default to green if no alerts match
    //                 ];
    //             })->filter()->values();

    //             return [
    //                 'device_id'           => (string) $device->id,
    //                 'device_profile_name' => (string) $device->deviceProfile->name,
    //                 'asset_id'            => (string) $device->asset_id,
    //                 'device_profile_id'   => (string) $device->device_profile_id,
    //                 'telemetry'           => $telemetry,
    //             ];
    //         });

    //         return response()->json([
    //             'telemetry' => $response,
    //             'time_range' => [
    //                 'startTs' => intval($startTsMs / 1000),
    //                 'endTs' => intval($endTsMs / 1000),
    //             ]
    //         ]);

    //     } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
    //         return response()->json([
    //             'error' => 'User not found',
    //             'code' => 'USER_NOT_FOUND'
    //         ], 404);
    //     } catch (\Exception $e) {
    //         Log::error('Telemetry data fetch failed: ' . $e->getMessage(), [
    //             'exception' => $e,
    //             'user_id' => $userId ?? null,
    //             'asset_id' => $assetId ?? null
    //         ]);

    //         return response()->json([
    //             'error' => 'Failed to fetch telemetry data',
    //             'code' => 'SERVER_ERROR'
    //         ], 500);
    //     }
    // }

    public function telemetryDataAsset(Request $request)
    {
        try {
            $token = readHeaderToken();
            $userId = $token['sub'];
            $customerId = User::where('id', $userId)->value('customer_id');

            $validator = Validator::make($request->all(), [
                'asset_id' => 'required|string',
            ]);

            if ($validator->fails()) {
                return jsonResponseWithErrorMessage($validator->errors()->first(), 400);
            }

            $assetId = $request->input('asset_id');

            if (!$this->validateAssetAccess($userId, $assetId)) {
                return response()->json([
                    'error' => 'You are not authorized to access this asset',
                    'code' => 'UNAUTHORIZED_ACCESS'
                ], 403);
            }

            $endTsMs = now()->timestamp * 1000;
            $startTsMs = $endTsMs - (30 * 60 * 1000);

            $devices = $this->getDevicesForAsset($assetId, $customerId);

            if ($devices->isEmpty()) {
                return response()->json([
                    'error' => 'No devices found for the specified asset',
                    'code' => 'DEVICES_NOT_FOUND'
                ], 404);
            }

            $response = $this->processDevicesTelemetry($devices, $startTsMs, $endTsMs);

            return response()->json([
                'telemetry' => $response,
                'time_range' => [
                    'startTs' => intval($startTsMs / 1000),
                    'endTs' => intval($endTsMs / 1000),
                ]
            ]);

        } catch (\Exception $e) {
            Log::error('Telemetry data fetch failed: ' . $e->getMessage());
            return response()->json([
                'error' => 'Failed to fetch telemetry data',
                'code' => 'SERVER_ERROR'
            ], 500);
        }
    }

    private function validateAssetAccess($userId, $assetId): bool
    {
        return UserAssetLink::where('user_id', $userId)
            ->where('asset_id', $assetId)
            ->exists();
    }

    private function getDevicesForAsset($assetId, $customerId)
    {
        return Device::with([
            'deviceProfile:id,name',
            'timeseriesKeys' => function ($query) {
                $query->where('display_on_dashboard', true)
                    ->orWhere('display_on_popup', true)
                    ->select(['id', 'device_profile_xid', 'key_name', 'display_name', 'display_on_dashboard', 'display_on_popup']);
            }
        ])->where('asset_id', $assetId)
          ->where('customer_id', $customerId)
          ->get();
    }

    private function processDevicesTelemetry($devices, $startTsMs, $endTsMs)
    {
        return $devices->map(function ($device) use ($startTsMs, $endTsMs) {
            $isActive = $this->checkDeviceActiveStatus($device);
            $keysData = $device->timeseriesKeys;
            $keyNames = $keysData->pluck('key_name')->toArray();

            $startTelemetry = [];
            $endTelemetry = [];

            if ($isActive) {
                $startTelemetry = $this->customerInfoService->getTelemetryData($device, $keyNames, $startTsMs, $startTsMs);
                $endTelemetry = $this->customerInfoService->getTelemetryData($device, $keyNames, $endTsMs, $endTsMs);
            }

            $alarmMap = $this->getDeviceAlarmsForTelemetry($device->id);
            $alertMessages = $this->getAlertMessages($keysData);

            $telemetry = $this->processTelemetryData($keysData, $startTelemetry, $endTelemetry, $alarmMap, $alertMessages, $isActive);

            return [
                'device_id'           => (string) $device->id,
                'device_name'         => (string) $device->deviceProfile->name,
                'device_profile_name' => (string) $device->deviceProfile->name,
                'asset_id'            => (string) $device->asset_id,
                'device_profile_id'   => (string) $device->device_profile_id,
                'is_active'           => $isActive,
                'telemetry'           => $telemetry,
            ];
        });
    }

    private function checkDeviceActiveStatus($device): bool
    {
        $deviceInfoToken = $this->adminService->getToken();
        if (!$deviceInfoToken) {
            return false;
        }

        $baseUrl = env('THINGSBOARD_URL');
        $deviceInfoResponse = Http::withHeaders([
            'Authorization' => "Bearer $deviceInfoToken",
            'Accept' => 'application/json',
        ])->get("{$baseUrl}api/device/info/{$device->id}");

        if ($deviceInfoResponse->successful()) {
            $deviceInfo = $deviceInfoResponse->json();
            return $deviceInfo['active'] ?? false;
        }

        Log::error("Failed to fetch device info for device ID: {$device->id}");
        return false;
    }

    private function getAlertMessages($keysData)
    {
        return TimeseriesAlertMessage::whereIn('timeseries_key_master_xid', $keysData->pluck('id'))
            ->orderBy('min_value', 'asc')
            ->get()
            ->groupBy('timeseries_key_master_xid');
    }

    private function processTelemetryData($keysData, $startTelemetry, $endTelemetry, $alarmMap, $alertMessages, $isActive)
    {
        return $keysData->map(function ($keyData) use ($startTelemetry, $endTelemetry, $alarmMap, $alertMessages, $isActive) {
            $startValue = 0;
            $endValue = 0;
            $timestamp = now()->timestamp;
            $trend = null;

            if ($isActive) {
                $startData = collect($startTelemetry[$keyData->key_name] ?? [])->last();
                $endData = collect($endTelemetry[$keyData->key_name] ?? [])->last();

                $startValue = floatval($startData['value'] ?? 0);
                $endValue = floatval($endData['value'] ?? 0);

                if ($startValue > 0) {
                    $trend = $this->determineTrend($endValue, $startValue);
                }

                $currentData = $endData ?? $startData ?? ['ts' => now()->timestamp * 1000];
                $timestamp = $this->formatTimestamp($currentData['ts']);
            }

            $colorCode = $this->determineColorCode($endValue, $alertMessages, $keyData->id, $isActive);

            return [
                'key_name'             => $keyData->key_name,
                'display_name'         => $keyData->display_name,
                'display_on_dashboard' => $keyData->display_on_dashboard,
                'display_on_popup'     => $keyData->display_on_popup,
                'timestamp'            => $timestamp,
                'value'                => $isActive ? $endValue : 0,
                'start_value'          => $isActive && $startValue > 0 ? $startValue : null,
                'trend'                => $trend,
                'alert'                => isset($alarmMap[$keyData->key_name]),
                'color_code'           => $colorCode,
            ];
        })->filter()->values();
    }

    private function determineTrend($endValue, $startValue): ?string
    {
        if ($endValue > $startValue) {
            return 'upward';
        } elseif ($endValue < $startValue) {
            return 'downward';
        }
        return 'stable';
    }

    private function formatTimestamp($ts): int
    {
        return is_float($ts) || $ts > 9999999999
            ? intval($ts / 1000)
            : $ts;
    }

    private function determineColorCode($endValue, $alertMessages, $keyId, $isActive): string
    {
        if (!$isActive) {
            return 'grey';
        }

        if ($endValue == 0) {
            return 'grey';
        }

        if (isset($alertMessages[$keyId])) {
            foreach ($alertMessages[$keyId] as $alertMsg) {
                if ((is_null($alertMsg->min_value) || $endValue >= floatval($alertMsg->min_value)) &&
                    (is_null($alertMsg->max_value) || $endValue <= floatval($alertMsg->max_value))) {
                    return $alertMsg->color_code;
                }
            }
        }

        return 'green';
    }

    private function getDeviceAlarmsForTelemetry($deviceId)
    {
        Log::info("Fetching alarms for device: {$deviceId}");

        $pageSize = 1000;
        $page = 0;

        // Fetch ThingsBoard token
        $token = $this->alarmService->getToken();
        if (!$token) {
            Log::error("Failed to fetch ThingsBoard token.");
            return [];
        }
        Log::info("Token fetched successfully.");

        $baseUrl = env('THINGSBOARD_URL');

        $endTime = now()->timestamp * 1000;                         // Current time in ms
        $startTime = now()->subHours(24)->timestamp * 1000;         // 24 hours ago in ms

        Log::info("Time range: Start => {$startTime}, End => {$endTime}");

        // Fetch alarms from ThingsBoard API
        try {
            $response = Http::withHeaders([
                'Authorization' => "Bearer $token",
                'Accept'        => 'application/json',
            ])->get("{$baseUrl}api/v2/alarms", [
                'statusList'   => 'ACTIVE',
                'severityList' => 'CRITICAL,MAJOR,MINOR,WARNING',
                'pageSize'     => $pageSize,
                'page'         => $page,
                'startTime'    => $startTime,
                'endTime'      => $endTime,
                'sortProperty' => 'createdTime',
                'sortOrder'    => 'DESC',
                'originator'   => $deviceId   // Filter by device ID
            ]);

            if (!$response->successful()) {
                Log::error("Failed to fetch alarms. Status: " . $response->status());
                return [];
            }

            // Parse the response
            $alarms = $response->json()['data'] ?? [];
            Log::info("Fetched " . count($alarms) . " alarms for device ID: {$deviceId}");

            // Map alarms by `type` field
            $alarmMap = [];
            foreach ($alarms as $alarm) {
                if (isset($alarm['type'])) {
                    $alarmMap[$alarm['type']] = true;
                }
            }

            Log::info("Mapped alarm types: ", $alarmMap);

            return $alarmMap;
        } catch (\Exception $e) {
            Log::error("Error fetching alarms: " . $e->getMessage());
            return [];
        }
    }






    // public function telemetryDataDevice(Request $request)
    // {
    //     try {

    //         $token = readHeaderToken();
    //         if (!$token) {
    //             return response()->json([
    //                 'success' => false,
    //                 'error' => 'Authorization token required'
    //             ], 401);
    //         }

    //         $validator = Validator::make($request->all(), [
    //             'device_id' => 'required|string',
    //             'startTs'  => 'nullable|string',
    //             'endTs'    => 'nullable|string',
    //         ]);

    //         if ($validator->fails()) {
    //             return response()->json([
    //                 'success' => false,
    //                 'error' => $validator->errors()->first()
    //             ], 400);
    //         }

    //         $deviceId = $request->input('device_id');
    //         $startTs = $request->input('startTs') ?: null;
    //         $endTs = $request->input('endTs') ?: null;

    //         try {
    //             $deviceWithTelemetry = Device::with([
    //                 'deviceProfile',
    //                 'timeseriesKeys' => function ($query) {
    //                     $query->select('key_name', 'display_name', 'device_profile_xid', 'display_on_dashboard','display_on_dashboard');
    //                 }
    //             ])
    //                 ->where('id', $deviceId)
    //                 ->firstOrFail();

    //             $telemetryResponse = $this->customerInfoService->getTelemetryDataDevice(
    //                 $deviceWithTelemetry,
    //                 $deviceWithTelemetry->timeseriesKeys->pluck('key_name')->toArray(),
    //                 $startTs,
    //                 $endTs,
    //                 $token
    //             );

    //             if (!is_array($telemetryResponse)) {
    //                 throw new \Exception("Invalid telemetry data format received from service");
    //             }

    //             $telemetry = collect($telemetryResponse)
    //                 ->flatMap(function ($items, $keyName) use ($deviceWithTelemetry) {
    //                     $displayName = $deviceWithTelemetry->timeseriesKeys
    //                         ->firstWhere('key_name', $keyName)?->display_name ?? $keyName;

    //                     return collect($items)->map(function ($item) use ($keyName, $displayName) {
    //                         return [
    //                             'key_name' => $keyName,
    //                             'timestamp' => $item['ts'] ?? null,
    //                             'value' => $item['value'] ?? null,
    //                             'display_name' => $displayName,
    //                             'display_on_dashboard'
    //                         ];
    //                     });
    //                 })
    //                 ->values()
    //                 ->all();

    //             return response()->json([
    //                 'success' => true,
    //                 'telemetry' => [
    //                     'device_id' => (string) $deviceWithTelemetry->id,
    //                     'device_name' => $deviceWithTelemetry->name,
    //                     'device_profile_name' => $deviceWithTelemetry->deviceProfile->name,
    //                     'device_profile_id' => (string) $deviceWithTelemetry->device_profile_id,
    //                     'telemetry_data' => $telemetry,
    //                 ]
    //             ], 200);
    //         } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
    //             return response()->json([
    //                 'success' => false,
    //                 'error' => 'Device not found'
    //             ], 404);
    //         } catch (\Exception $e) {
    //             return response()->json([
    //                 'success' => false,
    //                 'error' => 'Failed to fetch telemetry data',
    //                 'details' => config('app.debug') ? $e->getMessage() : null
    //             ], 503);
    //         }
    //     } catch (\Exception $e) {
    //         return response()->json([
    //             'success' => false,
    //             'error' => 'Internal server error',
    //             'details' => config('app.debug') ? $e->getMessage() : null
    //         ], 500);
    //     }
    // }

    public function telemetryDataDevice(Request $request)
    {
        try {
            $token = readHeaderToken();
            $customerId = User::where('id', $token['sub'])->value('customer_id');

            Log::info('Telemetry request received', ['request_data' => $request->all()]);

            if (!$token) {
                Log::warning('Unauthorized access attempt: Missing token');
                return response()->json([
                    'success' => false,
                    'error'   => 'Authorization token required'
                ], 401);
            }

            $validator = Validator::make($request->all(), [
                'device_id' => 'required|string',
                'startTs'   => 'nullable|string',
                'endTs'     => 'nullable|string',
            ]);

            if ($validator->fails()) {
                Log::error('Validation failed', ['errors' => $validator->errors()]);
                return response()->json([
                    'success' => false,
                    'error'   => $validator->errors()->first()
                ], 400);
            }

            $deviceId = $request->input('device_id');
            $startTs = $request->input('startTs') ?: null;
            $endTs = $request->input('endTs') ?: null;

            $device = $this->getDeviceWithTelemetryKeys($deviceId, $customerId);
            $displayKeys = $device->timeseriesKeys->pluck('key_name')->toArray();
            $deviceProfileName = strtolower($device->deviceProfile->name ?? '');

            Log::info('Device profile and keys retrieved', [
                'device_profile' => $deviceProfileName,
                'display_keys'   => $displayKeys
            ]);

            // Check pressure value for specific device profiles
            $pressureActive = $this->checkPressureValue(
                $device,
                $deviceProfileName,
                $displayKeys,
                $startTs,
                $endTs
            );

            $telemetryResponse = $this->customerInfoService->getTelemetryDataDevice(
                $device,
                $displayKeys,
                $startTs,
                $endTs,
                $token
            );

            if (!is_array($telemetryResponse)) {
                Log::error('Invalid telemetry data format received');
                throw new \Exception("Invalid telemetry data format received from service");
            }

            $filteredResponse = $this->filterTelemetryResponse($telemetryResponse, $displayKeys, $pressureActive);
            $telemetry = $this->formatDeviceTelemetry($filteredResponse, $device);

            Log::info('Telemetry response successfully generated', ['device_id' => $deviceId]);

            return response()->json([
                'success' => true,
                'telemetry' => [
                    'device_id'            => (string) $device->id,
                    'device_name'          => $device->name,
                    'device_profile_name'  => $device->deviceProfile->name,
                    'device_profile_id'    => (string) $device->device_profile_id,
                    'pressure_value'       => $pressureActive,
                    'telemetry_data'       => $telemetry,
                ]
            ], 200);
        } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
            Log::error('Device not found', ['device_id' => $deviceId ?? null]);
            return response()->json([
                'success' => false,
                'error'   => 'Device not found'
            ], 404);
        } catch (\Exception $e) {
            Log::critical('Internal server error', ['error' => $e->getMessage()]);
            return response()->json([
                'success' => false,
                'error'   => 'Internal server error',
                'details' => config('app.debug') ? $e->getMessage() : null
            ], 500);
        }
    }

    private function getDeviceWithTelemetryKeys($deviceId, $customerId)
    {
        return Device::with([
            'deviceProfile',
            'timeseriesKeys' => function ($query) {
                $query->where(function ($q) {
                    $q->where('display_on_dashboard', true)
                        ->orWhere('display_on_popup', true);
                })
                ->select('key_name', 'display_name', 'device_profile_xid', 'display_on_dashboard', 'display_on_popup');
            }
        ])
        ->where('id', $deviceId)
        ->where('customer_id', $customerId)
        ->firstOrFail();
    }

    private function checkPressureValue($device, $deviceProfileName, $displayKeys, $startTs, $endTs)
    {
        $pressureKey = 'Pressure_value';
        $pressureActive = false;

        // Check if the device has "Gas Engine Profile" or "Engine Profile" in its profile name
        if (strpos($deviceProfileName, 'gas engine profile') !== false ||
            strpos($deviceProfileName, 'engine profile') !== false) {

            $token = readHeaderToken();
            $pressureResponse = $this->customerInfoService->getTelemetryDataDevice(
                $device,
                [$pressureKey],
                $startTs,
                $endTs,
                $token
            );

            if (isset($pressureResponse[$pressureKey]) && is_array($pressureResponse[$pressureKey])) {
                foreach ($pressureResponse[$pressureKey] as $pressureData) {
                    if (!empty($pressureData['value']) && floatval($pressureData['value']) > 0) {
                        $pressureActive = true;
                        break;
                    }
                }
            }
        }

        return $pressureActive;
    }

    private function filterTelemetryResponse($telemetryResponse, $displayKeys, $pressureActive)
    {
        // Filter telemetry data based on display keys
        $filteredResponse = array_intersect_key($telemetryResponse, array_flip($displayKeys));

        // Add Pressure key if condition is met
        $pressureKey = 'Pressure_value';
        if ($pressureActive && isset($telemetryResponse[$pressureKey])) {
            $filteredResponse[$pressureKey] = $telemetryResponse[$pressureKey];
        }

        return $filteredResponse;
    }

    private function formatDeviceTelemetry($filteredResponse, $device)
    {
        return collect($filteredResponse)
            ->flatMap(function ($items, $keyName) use ($device) {
                $keyData = $device->timeseriesKeys->firstWhere('key_name', $keyName);

                return collect($items)->map(function ($item) use ($keyName, $keyData) {
                    return [
                        'key_name'              => $keyName,
                        'timestamp'             => $item['ts'] ?? null,
                        'value'                 => $item['value'] ?? null,
                        'display_name'          => $keyData->display_name ?? $keyName,
                        'display_on_dashboard'  => $keyData->display_on_dashboard ?? false,
                        'display_on_popup'      => $keyData->display_on_popup ?? false
                    ];
                });
            })
            ->values()
            ->all();
    }

    public function convertToUserTimezone($utcDatetime, $userTimezone = 'Asia/Kolkata', $format = 'd-M-Y H:i:s')
    {
        return Carbon::parse($utcDatetime, 'UTC')
                    ->setTimezone($userTimezone)
                    ->format($format);
    }

    public function entityQuery(){
        try {
            $token = readHeaderToken();

            // Retrieve devices of user
            $deviceIds = $this->getUserDeviceIds($token['sub']);

            // Retrieve required timeseries of devices
            $timeseriesKeys = $this->getAllDashboardTimeseriesKeys();

            $entityQuery = $this->customerInfoService->fetchEntityQuery($deviceIds, $timeseriesKeys);

            // Ensure the response is converted to an array if it's a JsonResponse
            $data = $entityQuery instanceof \Illuminate\Http\JsonResponse ? $entityQuery->getData(true) : $entityQuery;

            $timeseriesKeyMap = $this->getTimeseriesKeysByProfile();

            // Process the array and format the output
            $formatted = [
                'success' => true,
                'data' => collect($data['data'])->map(function ($device) use ($timeseriesKeyMap) {
                    $deviceType = $device['latest']['ENTITY_FIELD']['type']['value'] ?? null;
                    $deviceProfileId = DeviceProfileMaster::where('name', $deviceType)->select('id')->first();
                    $allTimeseries = $device['latest']['TIME_SERIES'] ?? [];

                    // Step 2: Get allowed keys for this device type
                    $allowedKeys = $timeseriesKeyMap[$deviceProfileId['id']] ?? [];

                    // Step 3: Filter timeseries to only include allowed keys
                    $filteredTimeseries = collect($allTimeseries)
                        ->only($allowedKeys)
                        ->toArray();

                    return [
                        'deviceId' => $device['entityId']['id'] ?? null,
                        'deviceName' => $device['latest']['ENTITY_FIELD']['name']['value'] ?? null,
                        'deviceProfileId' => $deviceProfileId['id'] ?? null,
                        'deviceType' => $deviceType,
                        'timeseries' => $filteredTimeseries,
                    ];
                })->toArray()
            ];

            return response()->json($formatted);

        } catch(Exception $e){
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    private function getUserDeviceIds($userId)
    {
        return UserAssetLink::with('asset.devices')
            ->where('user_id', $userId)
            ->get()
            ->pluck('asset.devices')
            ->flatten()
            ->pluck('id')
            ->toArray();
    }

    private function getAllDashboardTimeseriesKeys()
    {
        return TimeseriesKeyMaster::where('display_on_dashboard', 1)
            ->orWhere('display_on_popup', 1)
            ->get()
            ->pluck('key_name')
            ->flatten()
            ->toArray();
    }

    private function getTimeseriesKeysByProfile()
    {
        return TimeseriesKeyMaster::where('display_on_dashboard', 1)
            ->orWhere('display_on_popup', 1)
            ->get()
            ->groupBy('device_profile_xid')
            ->map(function ($group) {
                return $group->pluck('key_name')->toArray();
            });
    }

    public function userAssetsNew(){
        try {
            $token = readHeaderToken();
            $userId = $token['sub'];

            // Set cache key per user
            $cacheKey = "user_assets_health_{$userId}";

            // Cache the response for 60 seconds
            $formattedData = Cache::remember($cacheKey, now()->addSeconds(value: 60), function () use ($userId) {
                $assetDeviceListing = UserAssetLink::with('asset.devices')
                    ->where(['user_id' => $userId, 'active' => 1])
                    ->get();

                return $assetDeviceListing->map(function ($link) {
                    $asset = $link->asset;
                    $deviceHealthStatuses = [];

                    $devicesData = $asset->devices->map(function ($device) use (&$deviceHealthStatuses) {
                        $deviceType = $device->type;
                        $telemetryValues = $this->getHealthConditionTelemetry($device);
                        $deviceHealth = $deviceType == 'Torque' ? 'green' : $this->telemetryService->getDeviceHealth($telemetryValues);
                        $deviceHealthStatuses[] = $deviceHealth;

                        return [
                            'deviceId'   => $device->id,
                            'deviceName' => $device->label,
                            'deviceHealth' => $deviceHealth
                        ];
                    })->values();

                    return [
                        'assetId'   => $asset->id,
                        'assetName' => $asset->name,
                        'assetHealth' => $deviceHealthStatuses ? $this->telemetryService->getAssetHealth($deviceHealthStatuses) : null,
                        'devices' => $devicesData
                    ];
                });
            });

            return response()->json(['success' => true, 'data' => $formattedData]);

        } catch(Exception $e){
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    private function getHealthConditionTelemetry($device)
    {
        $timeseriesKeys = TimeseriesKeyMaster::where('display_on_health_condition', 1)
            ->where('device_profile_xid', $device->device_profile_id)
            ->pluck('key_name')
            ->implode(',');

        $telemetryValue = $this->customerInfoService->fetchTelemetryData($device->id, $timeseriesKeys);
        $data = $telemetryValue instanceof \Illuminate\Http\JsonResponse ? $telemetryValue->getData(true) : $telemetryValue;

        $transformedTelemetry = [];
        if (!empty($data) && is_array($data)) {
            foreach ($data as $key => $items) {
                foreach ($items as $item) {
                    $transformedTelemetry[] = [
                        'key_name' => $key,
                        'value' => $item['value']
                    ];
                }
            }
        }

        return $transformedTelemetry;
    }

    public function customerDeviceInfoNew()
    {
        try {
            $token = readHeaderToken();
            $cacheKey = 'device_info_' . $token['sub'];

            // Cache the entire response for 15 minutes
            // $response = Cache::remember($cacheKey, now()->addMinutes(value: 15), function () use ($token) {
                $devices = UserAssetLink::with('asset.devices')
                    ->where(['user_id' => $token['sub'], 'active' => 1])
                    ->get()
                    ->pluck('asset.devices')
                    ->flatten()
                    ->unique('id');

                $good = $moderate = $bad = 0;
                $deviceIds = $devices->pluck('id')->toArray();

                if (!empty($deviceIds)) {
                    foreach ($deviceIds as $deviceId) {
                        $device = Device::find($deviceId);
                        if ($device) {
                            $deviceType = $device->type;
                            $telemetryValues = $this->getHealthConditionTelemetry($device);
                            $deviceHealth = $deviceType == 'Torque' ? 'green' : $this->telemetryService->getDeviceHealth($telemetryValues);

                            match ($deviceHealth) {
                                'green' => $good++,
                                'orange' => $moderate++,
                                default => $bad++
                            };
                        }
                    }

                    $deviceCount = $this->customerInfoService->getDevicesCount($deviceIds);
                    $alarms = $this->customerInfoService->fetchDeviceAlarms($deviceIds);
                }

                $response = [
                    'success' => true,
                    'good' => $good,
                    'moderate' => $moderate,
                    'bad' => $bad,
                    'total' => $deviceCount['totalDevices'] ?? 0,
                    'active' => $deviceCount['activeDevices'] ?? 0,
                    'alarm' => $alarms['count'] ?? 0
                ];
            // });

            return response()->json($response);

        } catch (Exception $e) {
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    public function getActiveDevicesList() {
    try {
        $token = readHeaderToken();
        $userId = $token['sub'];

        $assetDeviceLinks = UserAssetLink::with('asset.devices')
            ->where(['user_id' => $userId, 'active' => 1])
            ->get();

        // Maintain order as per userAssetsNew
        $orderedDeviceIds = [];

        foreach ($assetDeviceLinks as $link) {
            foreach ($link->asset->devices as $device) {
                $orderedDeviceIds[] = $device->id;
            }
        }

        // Remove duplicates while keeping order
        $orderedDeviceIds = array_values(array_unique($orderedDeviceIds));

        // Fetch only active devices
        $activeDevices = $this->customerInfoService->getActiveDevicesList($orderedDeviceIds);
        $activeDeviceIds = collect($activeDevices['activeDevices'])->pluck('entityId')->pluck('id')->toArray();

        // Intersect ordered list with active IDs while preserving order
        $orderedActiveDeviceIds = array_values(array_filter($orderedDeviceIds, function ($id) use ($activeDeviceIds) {
            return in_array($id, $activeDeviceIds);
        }));

        // Fetch device details
        $getDevices = Device::with(['asset', 'customer'])
            ->whereIn('id', $orderedActiveDeviceIds)
            ->get(['id', 'name', 'label', 'asset_id', 'customer_id', 'type', 'created_at']);

        // Maintain order
        $deviceMap = $getDevices->keyBy('id');
        $liveDevices = collect($orderedActiveDeviceIds)->map(function ($id) use ($deviceMap) {
            $device = $deviceMap[$id] ?? null;
            if (!$device) return null;

            return [
                'deviceId' => $device->id,
                'assetName' => $device->asset->name ?? 'N/A',
                'deviceName' => $device->label,
                'deviceType' => $device->type,
                'deviceCustomer' => $device->customer->title ?? 'N/A',
                'deviceCreatedAt' => $device->created_at ?? 'N/A'
            ];
        })->filter(); // remove nulls

        // Count
        $deviceCount = $this->customerInfoService->getDevicesCount($orderedDeviceIds);

        return response()->json([
            'success' => true,
            'totalDevices' => $deviceCount['totalDevices'] ?? 0,
            'activeDevices' => $deviceCount['activeDevices'] ?? 0,
            'data' => $liveDevices
        ]);
    } catch (Exception $e) {
        return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
    }
}



    public function getDeviceIndicators($assetId){
        try {
            $token = readHeaderToken();
            $cacheKey = "device_indicators_{$token['sub']}_asset_{$assetId}";

            // Cache the response for 60 seconds
            $cachedData = Cache::remember($cacheKey, now()->addSeconds(value: 60), function () use ($token, $assetId) {
                $assetDeviceListing = $this->getUserAssetLinkWithDevices($token['sub'], $assetId);

                return $assetDeviceListing->map(function($link){
                    $asset = $link->asset;
                    $deviceData = $asset->devices->map(function($device){
                        $deviceProfile = $this->getDeviceWithProfile($device->id);
                        $deviceProfileId = $deviceProfile?->deviceProfile?->id;
                        $deviceProfileName = $deviceProfile?->deviceProfile?->name;

                        $timeseriesList = $this->getDashboardTimeseriesKeysForProfile($deviceProfileId);
                        $keyNameList = $timeseriesList->pluck('key_name')->implode(',');
                        $displayNameMap = $timeseriesList->pluck('display_name', 'key_name')->toArray();

                        $telemetryValue = $this->customerInfoService->fetchTelemetryData($device->id, $keyNameList);
                        $data = $telemetryValue instanceof \Illuminate\Http\JsonResponse ? $telemetryValue->getData(true) : $telemetryValue;

                        $transformedTelemetry = $this->processDeviceIndicators($data, $device->id, $device->type, $displayNameMap);

                        return [
                            'deviceId'      => $device->id,
                            'deviceName'    => $device->label,
                            'deviceType'    => $deviceProfileName,
                            'deviceSensor'  => $device->sensor,
                            'indicator'     => $transformedTelemetry
                        ];
                    })->values();

                    return [
                        'success'   => true,
                        'data'      => $deviceData
                    ];
                });

                // return $assetLink;
            });

            return response()->json($cachedData);

        } catch(Exception $e) {
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    private function getUserAssetLinkWithDevices($userId = null, $assetId = null)
    {
        $query = UserAssetLink::with('asset.devices')
            ->where('user_id', $userId);

        if ($assetId) {
            $query->where('asset_id', $assetId);
        }

        return $query->get();
    }

    private function getDeviceWithProfile($deviceId)
    {
        return Device::with('deviceProfile')->find($deviceId);
    }

    private function getDashboardTimeseriesKeysForProfile($deviceProfileId)
    {
        return TimeseriesKeyMaster::where('display_on_dashboard', true)
            ->where('device_profile_xid', $deviceProfileId)
            ->orderBy('display_on_popup_sequence','asc')
            ->get(['key_name', 'display_name']);
    }

    private function processDeviceIndicators($data, $deviceId, $deviceType, $displayNameMap)
    {
        $transformedTelemetry = [];

        if (!empty($data) && is_array($data)) {
            foreach ($data as $key => $items) {
                foreach ($items as $item) {
                    $color = $deviceType == 'Torque' ? 'green' : $this->determineIndicatorColor($key, $item['value']);

                    // Calculate average over past 6 hours
                    $averageVal = $this->calculateAverageOverPastHours($deviceId, $key, 6);

                    $transformedTelemetry[] = [
                        'display_name'  => $displayNameMap[$key] ?? $key,
                        'value'         => $this->telemetryService->getTypeWiseValue($key, $item['value']),
                        'averageVal'    => $this->telemetryService->getTypeWiseValue($key, $averageVal),
                        'color'         => $color
                    ];
                }
            }
        }

        return $transformedTelemetry;
    }

    private function determineIndicatorColor($key, $value)
    {
        if ($key == "PowerLoss_value") {
            if ($value > 5) {
                return 'red';
            } elseif ($value > 30) {
                return 'orange';
            }
            return 'green';
        }

        if ($key == "GlobalLevel_value") {
            if ($value > 7) {
                return 'red';
            } elseif ($value > 4) {
                return 'orange';
            }
            return 'green';
        }

        if ($value > 70) {
            return 'green';
        } elseif ($value > 30) {
            return 'orange';
        }
        return 'red';
    }

    private function calculateAverageOverPastHours($deviceId, $key, $hours = 6)
    {
        $ts['startTs'] = Carbon::now()->subHours($hours)->timestamp * 1000;
        $ts['endTs'] = Carbon::now()->timestamp * 1000;

        $pastValues = $this->customerInfoService->fetchTelemetryData($deviceId, $key, $ts);

        $pastValTotal = 0;
        $pastValTotalCount = 0;

        if (!empty($pastValues)) {
            foreach ($pastValues as $past) {
                foreach ($past as $value) {
                    $pastValTotal += $value['value'];
                    $pastValTotalCount++;
                }
            }
        }

        return $pastValTotalCount > 0 ? round($pastValTotal / $pastValTotalCount, 2) : 0;
    }

    public function getAlerts($deviceId){
        try {
            $token = readHeaderToken();
            $cacheKey = "device_alerts_{$token['sub']}_device_{$deviceId}";

            if (!$this->validateUserHasAccessToDevice($token['sub'], $deviceId)) {
                return response()->json(['success' => true, 'message' => 'Device not found'], 404);
            }

            // $cachedData = Cache::remember($cacheKey, now()->addHours(value: 1), function () use ($deviceId) {
                $deviceParams = $this->getDeviceAlertParameters($deviceId);

                $keyNameList = $deviceParams->pluck('key_name')->implode(',');
                $displayNameMap = $deviceParams->pluck('display_name', 'key_name')->toArray();

                $telemetryValue = $this->customerInfoService->fetchTelemetryData($deviceId, $keyNameList);
                $data = $telemetryValue instanceof \Illuminate\Http\JsonResponse ? $telemetryValue->getData(true) : $telemetryValue;

                $transformedTelemetry = [];
                $dateTime = null;

                if (!empty($data) && is_array($data)) {
                    foreach ($data as $key => $items) {
                        foreach ($items as $item) {
                            $alertPoints = $this->getAlertPointsForKey($key, $item['value'], $displayNameMap);
                            $dateTime = Carbon::createFromTimestamp($item['ts'] / 1000)->format('d-M-Y H:i:s');

                            if($alertPoints){
                                $transformedTelemetry[] = [
                                    'display_name' => $displayNameMap[$key] ?? $key,
                                    'alert_msg'    => $alertPoints ?: ["No Alerts & Instructions"]
                                ];
                            }
                        }
                    }
                }

                $response = [
                    'success'       => true,
                    'updated_time'  => $this->telemetryService->convertToUserTimezone($dateTime),
                    'data'          => $transformedTelemetry
                ];
            // });

            return response()->json($response);

        } catch(Exception $e){
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    private function validateUserHasAccessToDevice($userId, $deviceId)
    {
        $userDevices = UserAssetLink::with('asset.devices')
            ->where('user_id', $userId)
            ->get()
            ->pluck('asset.devices')
            ->flatten()
            ->unique('id');

        $deviceIds = $userDevices->pluck('id')->toArray();

        return in_array($deviceId, $deviceIds);
    }

    private function getDeviceAlertParameters($deviceId)
    {
        return TimeseriesKeyMaster::select('key_name', 'display_name')
            ->where('display_on_alerts', 1)
            ->whereHas('device', function ($query) use ($deviceId) {
                $query->where('id', $deviceId);
            })
            ->get();
    }

    private function getAlertPointsForKey($key, $value, $displayNameMap)
    {
        $displayName = $displayNameMap[$key] ?? $key;
        $timeseriesId = TimeseriesKeyMaster::where('display_name', $displayName)->first('id');

        if (!$timeseriesId) {
            return [];
        }

        $fetchMsg = TimeseriesAlertMessage::where('timeseries_key_master_xid', $timeseriesId['id'])
            ->where('min_value', '<=', $value)
            ->where('max_value', '>=', $value)
            ->first(['alert_msg']);

        return !empty($fetchMsg?->alert_msg) ? explode("\n", trim($fetchMsg->alert_msg)) : [];
    }

    public function getLiveDevice($deviceId){
        try {
            if (!$this->validateUserHasAccessToDevice(readHeaderToken()['sub'], $deviceId)) {
                return response()->json([
                    'success' => false,
                    'error' => 'You are not authorized to access this device'
                ], 403);
            }

            $deviceType = Device::where('id', $deviceId)->first('type');
            $deviceCount = $this->customerInfoService->getDevicesCount(["$deviceId"]);

            return response()->json([
                'success' => true,
                'active'  => $deviceCount['activeDevices'] ? true : false,
                'deviceType' => $deviceType->type
            ]);

        } catch(Exception $e){
            Log::error("Error checking device status: " . $e->getMessage(), ['device_id' => $deviceId]);
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    public function getGlobalIndicators($deviceId){
        try {
            $token = readHeaderToken();
            $cacheKey = "global_indicators_{$token['sub']}_device_{$deviceId}";

            if (!$this->validateUserHasAccessToDevice($token['sub'], $deviceId)) {
                return response()->json([
                    'success' => false,
                    'error' => 'Device not found or you do not have access to it'
                ], 404);
            }

            // Cache the response for 60 seconds
            $cachedData = Cache::remember($cacheKey, now()->addSeconds(value: 60), function () use ($deviceId) {
                $deviceParams = $this->getPopupTimeseriesKeys($deviceId);

                $keyNameList = $deviceParams->pluck('key_name')->implode(',');
                $displayNameMap = $deviceParams->pluck('display_name', 'key_name')->toArray();

                $telemetryValue = $this->customerInfoService->fetchTelemetryData($deviceId, $keyNameList);
                $data = $telemetryValue instanceof \Illuminate\Http\JsonResponse ? $telemetryValue->getData(true) : $telemetryValue;
                $deviceLiveStatus = $this->getLiveDevice($deviceId);
                $deviceLiveStatus = $deviceLiveStatus instanceof \Illuminate\Http\JsonResponse ? $deviceLiveStatus->getData(true) : $deviceLiveStatus;

                // Transform the data using our TelemetryService
                $transformed = $this->telemetryService->transformTelemetryData($deviceId, $data, $displayNameMap, $deviceLiveStatus['active']);

                return [
                    'success'       => true,
                    'updated_time'  => $transformed['dateTime'] ? $this->telemetryService->convertToUserTimezone($transformed['dateTime']) : null,
                    'data'          => $transformed['telemetry']
                ];
            });

            return response()->json($cachedData);

        } catch(Exception $e){
            Log::error("Error fetching global indicators: " . $e->getMessage(), ['device_id' => $deviceId]);
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    private function getPopupTimeseriesKeys($deviceId)
    {
        return TimeseriesKeyMaster::select('key_name', 'display_name', 'display_on_popup_sequence')
            ->where('display_on_popup', 1)
            ->whereHas('device', function ($query) use ($deviceId) {
                $query->where('id', $deviceId);
            })
            ->orderBy('display_on_popup_sequence')
            ->get();
    }

    public function getTrends($deviceId)
    {
        try {
            $token = readHeaderToken();
            $cacheKey = "trends_{$token['sub']}_device_{$deviceId}";

            $userDevices = UserAssetLink::with('asset.devices')
                ->where('user_id', $token['sub'])
                ->get()
                ->pluck('asset.devices')
                ->flatten()
                ->unique('id');
            $deviceIds = $userDevices->pluck('id')->toArray();

            if (!in_array($deviceId, $deviceIds)) {
                return response()->json(['success' => true, 'message' => 'Device not found'], 404);
            }

            // Cache the response for 60 seconds
            $cachedData = Cache::remember($cacheKey, now()->addSeconds(value: 60), function () use ($deviceId) {
                $dates = collect(range(0, 6))->map(function ($i) {
                    return Carbon::now()->subDays($i)->format('M d, Y');
                })->reverse()->values()->toArray();

                $graph1 = $graph2 = [];
                foreach ($dates as $date) {
                    $dateTs[] = Carbon::createFromFormat('M d, Y', $date)->timestamp * 1000;
                    $ts['startTs'] = Carbon::createFromFormat('M d, Y', $date)->startOfDay()->timestamp * 1000;
                    $ts['endTs'] = Carbon::createFromFormat('M d, Y', $date)->endOfDay()->timestamp * 1000;

                    $deviceProfile = Device::with('deviceProfile')->find($deviceId);
                    $deviceProfileId = $deviceProfile?->deviceProfile?->id;

                    $parameters = parameters();

                    $value1 = $value2 = [];
                    $key1 = explode(',', $parameters[$deviceProfileId]['keyNameList1']);
                    $key2 = explode(',', $parameters[$deviceProfileId]['keyNameList2']);

                    // For $key1 array
                    if (count($key1) === 3) {
                        $x1[0] = TimeseriesKeyMaster::where('key_name', $key1[0])->first('display_name');
                        $x1[1] = TimeseriesKeyMaster::where('key_name', $key1[1])->first('display_name');
                        $x2 = array_key_exists(1, $key1) ? TimeseriesKeyMaster::where('key_name', $key1[2])->first('display_name') : null;
                    } else {
                        $x1 = TimeseriesKeyMaster::where('key_name', $key1[0])->first('display_name');
                        $x2 = array_key_exists(1, $key1) ? TimeseriesKeyMaster::where('key_name', $key1[1])->first('display_name') : null;
                    }


                    // For $key2 array
                    if (count($key2) === 3) {
                        $y1[0] = TimeseriesKeyMaster::where('key_name', $key2[0])->first('display_name');
                        $y1[1] = TimeseriesKeyMaster::where('key_name', $key2[1])->first('display_name');
                        $y2 = array_key_exists(1, $key2) ? TimeseriesKeyMaster::where('key_name', $key2[2])->first('display_name') : null;
                    } else {
                        $y1 = TimeseriesKeyMaster::where('key_name', $key2[0])->first('display_name');
                        $y2 = array_key_exists(1, $key2) ? TimeseriesKeyMaster::where('key_name', $key2[1])->first('display_name') : null;
                    }

                    if($key1[0] === 'PowerLoss_value' || $key1[0] === 'GlobalLevel_value'){
                        $min1 = 0;
                        $max1 = 10;
                    } else if($key1[0] === 'StaticTorque_value'){
                        $min1 = 0;
                        $max1 = 500000;
                    } else {
                        $min1 = 0;
                        $max1 = 100;
                    }

                    if($key2[0] === 'StaticPower_value'){
                        $min2 = 0;
                        $max2 = 500000;
                    } else if($key2[0] === 'TDN'){
                        $min2 = 0;
                        $max2 = 1500;
                    } else {
                        $min2 = 0;
                        $max2 = 100;
                    }


                    // $min1 = $key1[0] === 'PowerLoss_value' ? 0 : 0;
                    // $max1 = $key1[0] === 'PowerLoss_value' ? 10 : 100;

                    $telemetryValue1 = app(CustomerInfoService::class)->fetchTelemetryData($deviceId, $parameters[$deviceProfileId]['keyNameList1'], $ts);
                    $trendsData1 = $telemetryValue1 instanceof \Illuminate\Http\JsonResponse ? $telemetryValue1->getData(true) : $telemetryValue1;

                    $telemetryValue2 = app(CustomerInfoService::class)->fetchTelemetryData($deviceId, $parameters[$deviceProfileId]['keyNameList2'], $ts);
                    $trendsData2 = $telemetryValue2 instanceof \Illuminate\Http\JsonResponse ? $telemetryValue2->getData(true) : $telemetryValue2;

                    if($trendsData1){
                    foreach ($trendsData1 as $key => $trend) {
                        $displayName = TimeseriesKeyMaster::where('key_name', $key)->first('display_name');
                        foreach ($trend as $val) {
                                $value1[0][$displayName['display_name']][] = $this->telemetryService->getTypeWiseValue($key, $val['value']);
                            }
                        }
                    }

                    if($trendsData2){
                    foreach ($trendsData2 as $key => $trend) {
                        $displayName = TimeseriesKeyMaster::where('key_name', $key)->first('display_name');
                        foreach ($trend as $val) {
                                $value2[0][$displayName['display_name']][] = $this->telemetryService->getTypeWiseValue($key, $val['value']);
                            }
                        }
                    }

                    $getLimit = Device::where('id', $deviceId)->select('speed_limit','torque_limit','power_limit')->first();

                    $graph1['y1'] = count($key1) === 3
                        ? [
                            'name' => [$x1[0]['display_name'], $x1[1]['display_name']],
                            'min' => $min1,
                            'max' => ($key1[0] === 'StaticTorque_value')
                                ? ($getLimit['speed_limit'] ?? $max1)
                                : $max1
                        ]
                        : [
                            'name' => [$x1['display_name']],
                            'min' => $min1,
                            'max' => ($key1[0] === 'StaticTorque_value')
                                ? ($getLimit['speed_limit'] ?? $max1)
                                : $max1
                        ];

                    $graph1['y2'] = $x2
                        ? [
                            'name' => [$x2['display_name']],
                            'min' => 0,
                            'max' => $getLimit['speed_limit'] ?? 50000
                        ]
                        : null;

                    $graph1[$date] = $value1;

                    $graph2['y1'] = count($key2) === 3
                        ? [
                            'name' => [$y1[0]['display_name'], $y1[1]['display_name']],
                            'min' => $min2,
                            'max' => ($key2[0] === 'StaticPower_value')
                                ? ($getLimit['speed_limit'] ?? $max2)
                                : $max2
                        ]
                        : [
                            'name' => [$y1['display_name']],
                            'min' => $min2,
                            'max' => ($key2[0] === 'StaticPower_value')
                                ? ($getLimit['speed_limit'] ?? $max2)
                                : $max2
                        ];

                    $graph2['y2'] = $y2
                        ? [
                            'name' => [$y2['display_name']],
                            'min' => 0,
                            'max' => $getLimit['speed_limit'] ?? 50000
                        ]
                        : null;

                    $graph2[$date] = $value2;

                }

                return [
                    'success' => true,
                    'graph1' => $graph1,
                    'graph2' => $graph2,
                ];
            });

            return response()->json($cachedData);

        } catch (Exception $e) {
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    public function getCylinderSpecificIndicators($deviceId) {
        try {
            $token = readHeaderToken();
            $cacheKey = "cylinder_specific_indicators_device_{$deviceId}";

            $userDevices = UserAssetLink::with('asset.devices')
                ->where('user_id', $token['sub'])
                ->get()
                ->pluck('asset.devices')
                ->flatten()
                ->unique('id');
            $deviceIds = $userDevices->pluck('id')->toArray();

            if (!in_array($deviceId, $deviceIds)) {
                return response()->json(['success' => true, 'message' => 'Device not found'], 404);
            }

            // $data = Cache::remember($cacheKey, now()->addHours(value: 1), function () use ($deviceId) {
                $device = Device::find($deviceId, ['device_profile_id', 'type']);
                $profileId = $device->device_profile_id;
                $isGasEngine = $device->type === 'Gas Engine';

                $cylindersToShow = ['Compression Condition','Injection Condition','Bearing Condition','Condition of Cyl Moving Parts'];
                if ($isGasEngine) {
                    $cylindersToShow[] = 'Misfiring';
                }

                $global = [
                    0 => 'Compression_valueInPercent',
                    1 => 'InjectionCondition_valueInPercent',
                    2 => 'Bearing_valueInPercent',
                    3 => 'BearingBis_valueInPercent',
                    4 => 'Misfiring_valueInPercent'
                ];

                $firingOrderKeys = TimeseriesKeyMaster::where('display_firing_order', 1)
                                    ->where('device_profile_xid', $profileId)
                                    ->pluck('key_name')
                                    ->toArray();

                $firingOrderData = app(CustomerInfoService::class)->fetchTelemetryData($deviceId, implode(',', $firingOrderKeys));
                $data = [];

                foreach ($cylindersToShow as $index => $title) {
                    $cylinderKeys = TimeseriesKeyMaster::where('display_cylinder_specific', $index + 1)
                                    ->where('device_profile_xid', $profileId)
                                    ->pluck('key_name')
                                    ->toArray();

                    $globalKey = $global[$index];
                    $colorData = app(CustomerInfoService::class)->fetchTelemetryData($deviceId, implode(',', $cylinderKeys));
                    $globalValue = app(CustomerInfoService::class)->fetchTelemetryData($deviceId, $globalKey);

                    $globalRaw = $globalValue[$globalKey][0]['value'] ?? 0;
                    $globalValueColor = $globalRaw > 70 ? 'green' : ($globalRaw > 30 ? 'orange' : 'red');

                    $response = [];
                    $i = 1;
                    foreach ($firingOrderData as $orderKey => $values) {
                        $cylinderNum = $values[0]['value'] ?? 0;
                        $name = 'Cyl' . $cylinderNum;

                        $prefixMap = [
                            0 => 'Compression',
                            1 => 'InjectionCondition',
                            2 => 'Bearing',
                            3 => 'BearingBis',
                            4 => 'Misfiring'
                        ];

                        $prefix = $prefixMap[$index];
                        $colorKey = "{$prefix}_cylinderValues_" . $i++;

                        $val = $colorData[$colorKey][0]['value'] ?? null;
                        $color = is_null($val) ? 'grey' : ($val > 70 ? 'green' : ($val > 30 ? 'orange' : 'red'));

                        $response[] = [
                            'name' => $name,
                            'value' => $val,
                            'color' => $color,
                        ];
                    }

                    $data[] = [
                        'title' => $title,
                        'global' => [
                            'value' => $globalRaw,
                            'color' => $globalValueColor,
                        ],
                        'data' => $response
                    ];
                }

                $response = ['success' => true, 'data' => $data];
            // });

            return response()->json($response);

        } catch (Exception $e) {
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    public function getPeakPressure($deviceId) {
        try {
            $token = readHeaderToken();
            $cacheKey = "peak_pressure_device_{$deviceId}";

            $userDevices = UserAssetLink::with('asset.devices')
                ->where('user_id', $token['sub'])
                ->get()
                ->pluck('asset.devices')
                ->flatten()
                ->unique('id');
            $deviceIds = $userDevices->pluck('id')->toArray();

            if (!in_array($deviceId, $deviceIds)) {
                return response()->json(['success' => true, 'message' => 'Device not found'], 404);
            }

            // $data = Cache::remember($cacheKey, now()->addHours(value: 1), function () use ($deviceId) {
                $device = Device::find($deviceId, ['device_profile_id', 'type']);
                $profileId = $device->device_profile_id;
                $pressureValKey = 'Pressure_value';

                $pressureVal = $this->customerInfoService->fetchTelemetryData($deviceId, $pressureValKey);
                    if ($pressureVal[$pressureValKey][0]['value'] == 0) {
                        return ['success' => false, 'message' => 'No data available'];
                    }

                $firingOrderKeys = TimeseriesKeyMaster::where('display_firing_order', 1)
                    ->where('device_profile_xid', $profileId)
                    ->pluck('key_name')
                    ->toArray();

                $cylinderKeys = TimeseriesKeyMaster::where('display_cylinder_specific', 6)
                    ->where('device_profile_xid', $profileId)
                    ->pluck('key_name')
                    ->toArray();

                $firingOrderData = app(CustomerInfoService::class)->fetchTelemetryData($deviceId, implode(',', $firingOrderKeys));
                $valData = app(CustomerInfoService::class)->fetchTelemetryData($deviceId, implode(',', $cylinderKeys));

                $i = 1;
                $response = [];

                foreach ($firingOrderData as $orderKey => $values) {
                    $cylinderNum = $values[0]['value'] ?? 0;
                    $name = 'Cyl' . $cylinderNum;

                    $valKey = "Pressure_cylinderHealth_" . $i++;
                    $val = $valData[$valKey][0]['value'] ?? null;

                    $response[] = [
                        'name'  => $name,
                        'value' => $val,
                    ];
                }

                $response = ['success' => true, 'data' => $response];
            // });

            return response()->json($response);

        } catch (Exception $e) {
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    public function getDeviceByAsset($assetId){
        $deviceList = Device::where('asset_id', $assetId)->select('id','name')->get()->toArray();
        return response()->json($deviceList);
    }

    public function getAdminAlarms(Request $request){
        try {
            if($request->assetIds){
                $getDeviceByAsset = Device::whereIn('asset_id', $request->assetIds)->pluck('id')->toArray();
            }else{
                $getDeviceByAsset = $request->deviceIds;
            }

            $data = [
                'statusList' => $request->statusList ?? ['ACTIVE'],
                'severityList' => $request->severityList,
                'startTs' => $request->startTs,
                'endTs' => $request->endTs,
                'deviceIds' => $request->deviceIds ?? $getDeviceByAsset,
            ];

            $allDevices = Device::pluck('id')->toArray();

            $alarms = $this->customerInfoService->fetchDeviceAlarms($allDevices, $data);

            return response()->json(['success' => true, 'data' => $alarms]);
        } catch(Exception $e){
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    public function getUserAssets(){
        $token = readHeaderToken();
        $userId = $token['sub'];

        $userAssets = UserAssetLink::with('asset:id,name')
            ->where(['user_id' => $userId, 'active' => 1])
            ->get()
            ->map(function($link) {
                return [
                    'id' => $link->asset->id,
                    'name' => $link->asset->name
                ];
            });
        return response()->json($userAssets);
    }

    public function getUserDeviceByAsset($assetId){
        $token = readHeaderToken();
        $userDevices = UserAssetLink::with('asset.devices')
                ->where(['user_id' => $token['sub'], 'active' => 1, 'asset_id' => $assetId])
                ->get()
                ->pluck('asset.devices')
                ->flatten()
                ->select('id','name','label');

        return response()->json($userDevices);
    }

    public function getUserAlarms(Request $request){
        try {
            $token = readHeaderToken();

            if($request->assetIds) {
                $userDevices = UserAssetLink::with('asset.devices')
                    ->where(['user_id' => $token['sub'], 'active' => 1])
                    ->whereIn('asset_id', $request->assetIds)
                    ->get()
                    ->pluck('asset.devices')
                    ->flatten()
                    ->unique('id');
                $getDeviceByAsset = $userDevices->pluck('id')->toArray();
            } else {
                $getDeviceByAsset = $request->deviceIds;
            }

            $data = [
                'statusList' => $request->statusList ?? ['ACTIVE'],
                'severityList' => $request->severityList,
                'startTs' => $request->startTs,
                'endTs' => $request->endTs,
                'deviceIds' => $request->deviceIds ?? $getDeviceByAsset,
            ];

            $userDevices = UserAssetLink::with('asset.devices')
                ->where(['user_id' => $token['sub'], 'active' => 1])
                ->get()
                ->pluck('asset.devices')
                ->flatten()
                ->unique('id');
            $allDevices = $userDevices->pluck('id')->toArray();

            $alarms = $this->customerInfoService->fetchDeviceAlarms($allDevices, $data);

            return response()->json(['success' => true, 'data' => $alarms]);
        } catch(Exception $e){
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

}
