<?php

namespace App\Services;

use App\Models\TimeseriesKeyMaster;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use App\Services\AdminService;
use Exception;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Cache;


class CustomerInfoService
{
    protected $adminService;

    public function __construct(AdminService $adminService)
    {
        $this->adminService = $adminService;
    }

    // public function getThingsBoardDevices($customerId)
    // {
    //     try {
    //         $token = $this->adminService->getToken();

    //         if (!$token) {
    //             Log::error("Failed to authenticate with ThingsBoard.");
    //             return response()->json([
    //                 'error' => 'thingsboard_auth_failed',
    //                 'message' => 'Failed to authenticate with ThingsBoard'
    //             ], 401);
    //         }

    //         $response = Http::withHeaders([
    //             'Authorization' => "Bearer $token",
    //             'Accept'        => 'application/json',
    //         ])->get("http://65.0.131.117:8080/api/customer/{$customerId}/deviceInfos?pageSize=100&page=0");

    //         if (!$response->successful()) {
    //             Log::error("Failed to fetch ThingsBoard devices: " . $response->body());
    //             return response()->json([
    //                 'error' => 'thingsboard_fetch_failed',
    //                 'message' => 'Failed to fetch devices from ThingsBoard',
    //                 'details' => $response->body()
    //             ], $response->status());
    //         }

    //         $data = $response->json();
    //         return $data['data'] ?? [];

    //     } catch (\Exception $e) {
    //         Log::error("Error fetching ThingsBoard devices: " . $e->getMessage());
    //         return response()->json([
    //             'error' => 'thingsboard_error',
    //             'message' => 'Error fetching devices from ThingsBoard',
    //             'details' => $e->getMessage()
    //         ], 500);
    //     }
    // }



    public function getTelemetryData($device, $keyNames, $startTs, $endTs)
    {
        $token = $this->adminService->getToken();

        if (!$token) {
            return ['error' => 'Failed to fetch ThingsBoard token'];
        }

        $baseUrl = env('THINGSBOARD_URL');
        $deviceId = $device->id;

        $keys = implode(',', $keyNames);

        // Build query parameters dynamically
        $queryParams = [
            'keys' => $keys,
        ];

        if ($startTs) {
            $queryParams['startTs'] = $startTs;
        }

        if ($endTs) {
            $queryParams['interval'] = $endTs;
        }

        // Make the HTTP request
        $response = Http::withHeaders([
            'Authorization' => "Bearer $token",
            'Accept'        => 'application/json',
        ])->get("{$baseUrl}api/plugins/telemetry/DEVICE/{$deviceId}/values/timeseries", $queryParams);

        // Check if the response was successful
        if (!$response->successful()) {
            Log::error("Failed to fetch telemetry for device: {$device->name} (ID: {$deviceId})", [
                'http_code' => $response->status(),
                'url'       => $response->effectiveUri(),
                'response'  => $response->body(),
            ]);

            return ['error' => "Failed to fetch telemetry. HTTP Code: " . $response->status()];
        }

        // Decode the telemetry response
        $telemetry = $response->json();
        Log::info("Telemetry Data", $telemetry);

        if (json_last_error() !== JSON_ERROR_NONE) {
            Log::error("Failed to decode telemetry response for device: {$device->name}", [
                'response' => $response->body(),
            ]);

            return ['error' => 'Invalid telemetry response format'];
        }

        return $telemetry;
    }



    public function getTelemetryDataDevice($device, $keyNames, $startTs, $endTs)
    {

        $token = $this->adminService->getToken();

        if (!$token) {
            Log::error('Failed to fetch ThingsBoard token');
            return ['error' => 'Failed to fetch ThingsBoard token'];
        }

        $baseUrl = env('THINGSBOARD_URL');
        $deviceId = $device->id;

        $keys = implode(',', $keyNames);


        $queryParams = [
            'keys' => $keys,
        ];

        if ($startTs) {
            $queryParams['startTs'] = $startTs;
        }

        if ($endTs) {
            $queryParams['endTs'] = $endTs;
        }

        $response = Http::withHeaders([
            'Authorization' => "Bearer $token",
            'Accept'        => 'application/json',
        ])->get("{$baseUrl}api/plugins/telemetry/DEVICE/{$deviceId}/values/timeseries", $queryParams);




        // Check if the response was successful
        if (!$response->successful()) {
            Log::error("Failed to fetch telemetry for device: {$device->name} (ID: {$deviceId})", [
                'http_code' => $response->status(),
                'url'       => $response->effectiveUri(),
                'response'  => $response->body()
            ]);

            return ['error' => "Failed to fetch telemetry. HTTP Code: " . $response->status()];
        }

        // Decode the telemetry response
        $telemetry = $response->json();

        if (json_last_error() !== JSON_ERROR_NONE) {
            Log::error("Failed to decode telemetry response for device: {$device->name}", [
                'response' => $response->body()
            ]);

            return ['error' => 'Invalid telemetry response format'];
        }

        return $telemetry;
    }


    public function getTelemetryDataDeviceDiagonostic($device, $keyNames, $startTs, $endTs)
    {

        $token = $this->adminService->getToken();

        if (!$token) {
            Log::error('Failed to fetch ThingsBoard token');
            return ['error' => 'Failed to fetch ThingsBoard token'];
        }

        $baseUrl = env('THINGSBOARD_URL');
        $deviceId = $device->id;

        $keys = implode(',', $keyNames);



        $response = Http::withHeaders([
            'Authorization' => "Bearer $token",
            'Accept'        => 'application/json'
            // ])->get("$baseUrl/api/plugins/telemetry/DEVICE/58bf81a0-0619-11f0-a9dc-45dd276e4cd5/values/timeseries", [
        ])->get("$baseUrl/api/plugins/telemetry/DEVICE/{$deviceId}/values/timeseries", [

            'keys'    => $keys,
            // 'keys'    => 'MechanicalHealth_valueInPercent',
            'startTs' => $startTs,
            'interval'   => $endTs,
            'limit'   => 100,
            'useStrictDataTypes'   => false
        ]);



        // Check if the response was successful
        if (!$response->successful()) {
            Log::error("Failed to fetch telemetry for device: {$device->name} (ID: {$deviceId})", [
                'http_code' => $response->status(),
                'url'       => $response->effectiveUri(),
                'response'  => $response->body()
            ]);

            return ['error' => "Failed to fetch telemetry. HTTP Code: " . $response->status()];
        }

        // Decode the telemetry response
        $telemetry = $response->json();

        if (json_last_error() !== JSON_ERROR_NONE) {
            Log::error("Failed to decode telemetry response for device: {$device->name}", [
                'response' => $response->body()
            ]);

            return ['error' => 'Invalid telemetry response format'];
        }

        return $telemetry;
    }



    public function getCustomerDevicesAndAlarms($customerId)
    {
        $result = [
            'devices' => [],
            'alarms' => [],
            'errors' => []
        ];

        try {
            // Step 1: Get devices
            $devicesResponse = $this->getThingsBoardDevices($customerId);

            if (isset($devicesResponse['error'])) {
                $result['errors']['devices'] = $devicesResponse;
            } else {
                $result['devices'] = $devicesResponse;

                // Step 2: Get alarms if devices were fetched successfully
                $deviceIds = array_column($devicesResponse, 'id.id');
                if (!empty($deviceIds)) {
                    $alarmsResponse = $this->getDeviceAlarms($deviceIds);

                    if (isset($alarmsResponse['error'])) {
                        $result['errors']['alarms'] = $alarmsResponse;
                    } else {
                        $result['alarms'] = $alarmsResponse['data'] ?? [];
                    }
                }
            }

            return $result;
        } catch (\Exception $e) {
            Log::error("ThingsBoard service error: " . $e->getMessage());
            return [
                'error' => 'service_error',
                'message' => 'Failed to complete ThingsBoard operation',
                'details' => $e->getMessage()
            ];
        }
    }

    /**
     * Get devices for a customer
     */
    private function getThingsBoardDevices($customerId)
    {
        try {
            $token = $this->adminService->getToken();
            if (!$token) {
                throw new \Exception("Failed to authenticate with ThingsBoard");
            }

            $response = Http::withHeaders([
                'Authorization' => "Bearer $token",
                'Accept' => 'application/json',
            ])->get("http://65.0.131.117:8080/api/customer/{$customerId}/deviceInfos?pageSize=100&page=0");

            if (!$response->successful()) {
                throw new \Exception("Failed to fetch devices: " . $response->body());
            }

            $data = $response->json();
            return $data['data'] ?? [];
        } catch (\Exception $e) {
            Log::error("Device fetch error: " . $e->getMessage());
            return [
                'error' => 'device_fetch_failed',
                'message' => 'Failed to fetch devices',
                'details' => $e->getMessage()
            ];
        }
    }

    /**
     * Get alarms for specific devices (last 24 hours)
     */
    private function getDeviceAlarms(array $deviceIds)
    {
        try {
            $token = $this->adminService->getToken();
            if (!$token) {
                throw new \Exception("Failed to authenticate with ThingsBoard");
            }

            $startTime = (time() - 86400) * 1000; // 24 hours ago in milliseconds
            $deviceIdsParam = implode(',', $deviceIds);

            $response = Http::withHeaders([
                'Authorization' => "Bearer $token",
                'Accept' => 'application/json',
            ])->get("http://65.0.131.117:8080/api/v2/alarms", [
                'pageSize' => 100,
                'page' => 0,
                'startTime' => $startTime,
                'deviceIds' => $deviceIdsParam
            ]);

            if (!$response->successful()) {
                throw new \Exception("Failed to fetch alarms: " . $response->body());
            }

            return $response->json();
        } catch (\Exception $e) {
            Log::error("Alarm fetch error: " . $e->getMessage());
            return [
                'error' => 'alarm_fetch_failed',
                'message' => 'Failed to fetch alarms',
                'details' => $e->getMessage()
            ];
        }
    }



    public function getToken()
    {
        $baseUrl = env('THINGSBOARD_URL', 'http://65.0.131.117:8080');
        $username = env('THINGSBOARD_USERNAME', 'tenant1@thingsboard.org');
        $password = env('THINGSBOARD_PASSWORD', 'tenant1');

        if (Cache::has('thingsboard_token')) {
            return Cache::get('thingsboard_token');
        }

        $response = Http::withHeaders([
            // 'accept' => 'application/json',
            'Content-Type' => 'application/json',
        ])
            ->post("{$baseUrl}api/auth/login", [
                'username' => $username,
                'password' => $password,
            ]);


        if ($response->successful()) {
            $token = $response->json('token');
            Cache::put('thingsboard_token', $token, now()->addMinutes(1440));
            return $token;
        } else {
            Log::error("ThingsBoard Authentication Failed: " . $response->body());
            throw new Exception('Unable to authenticate with ThingsBoard: ' . $response->body());
        }
    }

    public function fetchEntityQuery($deviceIds, $timeseriesKeys){
        try{
            $token = $this->adminService->getToken();
            if (!$token) {
                throw new \Exception("Failed to authenticate with ThingsBoard");
            }

            $url = env('THINGSBOARD_URL').'api/entitiesQuery/find';

            $timeSeries = array_map(function($key) {
                return [
                    'type' => 'TIME_SERIES',
                    'key' => $key
                ];
            }, $timeseriesKeys);

            $payload = [
                "entityFilter" => [
                    "type" => "entityList",
                    "entityType" => "DEVICE",
                    "entityList" => $deviceIds
                ],
                "pageLink" => [
                    "pageSize" => 100,
                    "page" => 0,
                    "textSearch" => "",
                    "dynamic" => true
                ],
                "entityFields" => [
                    ["type" => "ENTITY_FIELD", "key" => "name"],
                    ["type" => "ENTITY_FIELD", "key" => "type"],
                ],
                "latestValues" => $timeSeries
            ];

            $response = Http::withHeaders([
                'accept' => 'application/json',
                'Content-Type' => 'application/json',
                'X-Authorization' => 'Bearer ' . $token,
            ])->post($url, $payload);

            // Return JSON response
            return response()->json($response->json(), $response->status());

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

    public function fetchTelemetryData($deviceId,$keys,$ts=[])
    {
        $url = env('THINGSBOARD_URL') ."api/plugins/telemetry/DEVICE/{$deviceId}/values/timeseries?useStrictDataTypes=false";

        $token = $this->adminService->getToken();
        if (!$token) {
            throw new \Exception("Failed to authenticate with ThingsBoard");
        }

        try {
            $response = Http::withToken($token)->asForm()->get($url, [
                'keys'      => $keys,
                'startTs'   => $ts['startTs'] ?? null,
                'endTs'     => $ts['endTs'] ?? null,
                'limit'     => 250
            ]);

            if ($response->successful()) {
                return $response->json();
            } else {
                return response()->json([
                    'success' => false,
                    'message' => 'Failed to fetch data',
                    'status' => $response->status(),
                ], $response->status());
            }
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'An error occurred: ' . $e->getMessage(),
            ], 500);
        }
    }
    public function getDevicesCount($deviceIds)
    {
        try {
            $token = $this->adminService->getToken();
            if (!$token) {
                throw new \Exception("Failed to authenticate with ThingsBoard");
            }

            $url = env('THINGSBOARD_URL') . 'api/entitiesQuery/find';

            $payload = [
                "entityFilter" => [
                    "type" => "entityList",
                    "entityType" => "DEVICE",
                    "entityList" => $deviceIds
                ],
                "keyFilters" => [
                    [
                        "key" => [
                            "type" => "ATTRIBUTE",
                            "key" => "active"
                        ],
                        "valueType" => "BOOLEAN",
                        "predicate" => [
                            "operation" => "EQUAL",
                            "value" => [
                                "defaultValue" => true,
                                "dynamicValue" => null
                            ],
                            "type" => "BOOLEAN"
                        ]
                    ]
                ],
                "pageLink" => [
                    "pageSize" => 100,
                    "page" => 0,
                    "sortOrder" => [
                        "key" => [
                            "type" => "ENTITY_FIELD",
                            "key" => "name"
                        ],
                        "direction" => "ASC"
                    ]
                ]
            ];

            $response = Http::withHeaders([
                'accept' => 'application/json',
                'Content-Type' => 'application/json',
                'X-Authorization' => 'Bearer ' . $token,
            ])->post($url, $payload);

            if ($response->successful()) {
                $data = $response->json();
                return [
                    'totalDevices' => count($deviceIds),
                    'activeDevices' => count($data['data'] ?? [])
                ];
            }

            return [
                'totalDevices' => count($deviceIds),
                'activeDevices' => 0
            ];

        } catch (\Exception $e) {
            Log::error('Failed to get devices count: ' . $e->getMessage());
            return [
                'totalDevices' => count($deviceIds),
                'activeDevices' => 0
            ];
        }
    }

    public function getActiveDevicesList($deviceIds){
        try {
            $token = $this->adminService->getToken();
            if (!$token) {
                throw new \Exception("Failed to authenticate with ThingsBoard");
            }

            $url = env('THINGSBOARD_URL') . 'api/entitiesQuery/find';

            $payload = [
                "entityFilter" => [
                    "type" => "entityList",
                    "entityType" => "DEVICE",
                    "entityList" => $deviceIds
                ],
                "keyFilters" => [
                    [
                        "key" => [
                            "type" => "ATTRIBUTE",
                            "key" => "active"
                        ],
                        "valueType" => "BOOLEAN",
                        "predicate" => [
                            "operation" => "EQUAL",
                            "value" => [
                                "defaultValue" => true,
                                "dynamicValue" => null
                            ],
                            "type" => "BOOLEAN"
                        ]
                    ]
                ],
                "pageLink" => [
                    "pageSize" => 100,
                    "page" => 0,
                    "sortOrder" => [
                        "key" => [
                            "type" => "ENTITY_FIELD",
                            "key" => "name"
                        ],
                        "direction" => "ASC"
                    ]
                ]
            ];

            $response = Http::withHeaders([
                'accept' => 'application/json',
                'Content-Type' => 'application/json',
                'X-Authorization' => 'Bearer ' . $token,
            ])->post($url, $payload);

            // if (!$response->successful()) {
            //     throw new \Exception("Failed to fetch active devices: " . $response->body());
            // }

            $activeDevices = $response->json();
            return [
                'activeDevices' => $activeDevices['data'] ?? [],
                'totalElements' => $activeDevices['totalElements'] ?? 0
            ];

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

public function fetchDeviceAlarms(array $deviceIds, $data=[])
    {
        try {
            $token = $this->adminService->getToken();
            if (!$token) {
                throw new \Exception("Failed to authenticate with ThingsBoard");
            }

            $url = env('THINGSBOARD_URL') . 'api/alarmsQuery/find';
            if (isset($data['startTs']) && isset($data['endTs'])) {
                $startDate = \DateTime::createFromFormat('d/m/Y', $data['startTs']);
                $endDate = \DateTime::createFromFormat('d/m/Y', $data['endTs']);

                if ($startDate && $endDate) {
                    $startTimestamp = $startDate->getTimestamp() * 1000;
                    $endTimestamp = $endDate->getTimestamp() * 1000;
                }
            }
            // Timestamp range (modify as needed)
            $startTs = $startTimestamp ?? now()->subHours(24)->timestamp * 1000;
            $endTs = $endTimestamp ?? now()->timestamp * 1000;
            $entityList = $data['deviceIds'] ?? $deviceIds;
            // dd($entityList);
            $payload = [
                "entityFilter" => [
                    "type" => "entityList",
                    "entityType" => "DEVICE",
                    "entityList" => $entityList
                ],
                "pageLink" => [
                    // "startTs" => $startTs,
                    // "endTs" => $endTs,
                    "pageSize" => 100,
                    "page" => 0,
                    "textSearch" => "",
                    "statusList" => $data['statusList'] ?? ['ACTIVE'],
                    "severityList" => $data['severityList'] ?? [],
                    "sortOrder" => [
                        "key" => [
                            "type" => "ALARM_FIELD",
                            "key" => "createdTime"
                        ],
                        "direction" => "DESC"
                    ]
                ],
                "alarmFields" => []
            ];

            $response = Http::withHeaders([
                'accept' => 'application/json',
                'Content-Type' => 'application/json',
                'X-Authorization' => 'Bearer ' . $token,
            ])->post($url, $payload);

            if (!$response->successful()) {
                throw new \Exception("Failed to fetch alarms: " . $response->body());
            }

            $alarmData = $response->json();

            return [
                'data'  => $alarmData['data'] ?? [],
                'count' => $alarmData['totalElements'] ?? 0
            ];

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


}
