<?php

namespace App\Services;

use App\Models\Device;
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;
use Carbon\Carbon;


class AlarmService
{
    protected $adminService;

    public function __construct(AdminService $adminService)
    {
        $this->adminService = $adminService;
        $this->baseUrl = env('THINGSBOARD_URL', 'http://65.0.131.117:8080');
        $this->username = env('THINGSBOARD_USERNAME', 'tenant1@thingsboard.org');
        $this->password = env('THINGSBOARD_PASSWORD', 'tenant1');
    }

    private $baseUrl;
    private $username;
    private $password;



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

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


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


    public function getAdminAlarm($data)
    {
        try {

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

            if (!$token) {
                Log::error("Failed to authenticate with ThingsBoard.");
                return [];
            }

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

            if (!$response->successful()) {
                Log::error("Failed to fetch ThingsBoard devices: " . $response->body());
                return [];
            }

            return $response->json()['data'] ?? [];
        } catch (\Exception $e) {
            Log::error("Error fetching ThingsBoard devices: " . $e->getMessage());
            return [];
        }
    }

    // public function getTelemetryData($devices, $startTs, $endTs, $limit = 100)
    // {
    //     try {
    //         // Get ThingsBoard token from AdminService
    //         $token = $this->adminService->getToken();

    //         if (!$token) {
    //             Log::error("Failed to authenticate with ThingsBoard.");
    //             return ['error' => 'Authentication failed'];
    //         }

    //         $baseUrl = env('THINGSBOARD_URL', 'http://65.0.131.117:8080');
    //         $telemetryData = [];

    //         foreach ($devices as $device) {
    //             $deviceToken = $device->token;

    //             // Include asset_id, device_profile_id, and device name
    //             $assetId = $device->asset_id;
    //             $deviceProfileId = $device->device_profile_id;
    //             $deviceName = $device->name;

    //             if (!$deviceToken) {
    //                 Log::warning("Device token missing for device: {$deviceName} (ID: {$device->id})");
    //                 continue;
    //             }

    //             $keys = $device->timeseriesKeys->pluck('key_name')->implode(',');

    //             if (empty($keys)) {
    //                 Log::warning("No telemetry keys found for device: {$deviceName} (Token: {$deviceToken})");
    //                 continue;
    //             }

    //             // Make the telemetry API call
    //             $response = Http::withHeaders([
    //                 'X-Authorization' => "Bearer $token",
    //                 'Accept' => 'application/json',
    //             ])->get("{$baseUrl}/api/plugins/telemetry/DEVICE/{$deviceToken}/values/timeseries", [
    //                 'keys' => $keys,
    //                 'startTs' => $startTs,
    //                 'endTs' => $endTs,
    //                 'limit' => $limit,
    //                 'useStrictDataTypes' => 'false',
    //             ]);

    //             if (!$response->successful()) {
    //                 Log::error("Failed to fetch telemetry for device: {$deviceName} (Token: {$deviceToken})");
    //                 continue;
    //             }

    //             $data = $response->json();

    //             // Format telemetry data with asset_id, device_profile_id, and name as key
    //             $formattedTelemetry = [];

    //             if (!empty($data)) {
    //                 foreach ($data as $key => $values) {
    //                     foreach ($values as $item) {
    //                         $formattedTelemetry[] = [
    //                             'key' => $key,
    //                             'value' => $item['value'],
    //                             'ts' => $item['ts']
    //                         ];
    //                     }
    //                 }
    //             }

    //             $telemetryData[] = [
    //                 'asset_id' => $assetId,
    //                 'device_profile_id' => $deviceProfileId,
    //                 'name' => $deviceName,
    //                 'telemetry' => $formattedTelemetry,
    //             ];
    //         }

    //         return $telemetryData;

    //     } catch (\Exception $e) {
    //         Log::error("Error fetching telemetry data: " . $e->getMessage());
    //         return ['error' => 'Failed to fetch telemetry data'];
    //     }
    // }

    // public function getTelemetryData($devices, $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');

    //     $headers = [
    //         'Authorization: Bearer ' . $token,
    //         'accept: application/json'
    //     ];

    //     $allTelemetry = [];

    //     foreach ($devices as $device) {
    //         $deviceId = $device->id;
    //         $keys = $device->timeseriesKeys->pluck('key_name')->filter()->implode(',');

    //         if (empty($keys)) {
    //             Log::warning("No telemetry keys found for device: {$device->name}");
    //             $allTelemetry[$deviceId] = [
    //                 'status' => 'error',
    //                 'message' => 'No telemetry keys found'
    //             ];
    //             continue;
    //         }

    //         $url = "$baseUrl/api/plugins/telemetry/DEVICE/{$deviceId}/values/timeseries"
    //             . "?keys={$keys}&startTs={$startTs}&endTs={$endTs}&limit=100";

    //         $ch = curl_init($url);
    //         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    //         curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

    //         $response = curl_exec($ch);
    //         $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    //         $error = curl_error($ch);
    //         curl_close($ch);

    //         if ($error || $httpCode !== 200) {
    //             Log::error("Failed to fetch telemetry for device: {$device->name} (ID: {$deviceId})", [
    //                 'http_code' => $httpCode,
    //                 'error' => $error,
    //                 'url' => $url,
    //                 'response' => $response
    //             ]);

    //             $allTelemetry[$deviceId] = [
    //                 'status' => 'error',
    //                 'message' => "Failed to fetch telemetry. HTTP Code: $httpCode, Error: $error"
    //             ];
    //             continue;
    //         }

    //         $telemetry = json_decode($response, true);

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

    //             $allTelemetry[$deviceId] = [
    //                 'status' => 'error',
    //                 'message' => 'Invalid telemetry response format'
    //             ];
    //             continue;
    //         }

    //         $allTelemetry[$deviceId] = [
    //             'status' => 'success',
    //             'telemetry' => $telemetry
    //         ];
    //     }

    //     return $allTelemetry;  // Return telemetry data mapped by device_id
    // }





    /**
     * Get telemetry data for a specific device and keys
     *
     * @param Device $device The device to get telemetry for
     * @param array $keyNames Array of telemetry keys to fetch
     * @param int $startTs Start timestamp
     * @param int $endTs End timestamp
     * @return array Telemetry data or error response
     */
    public function getTelemetryData(Device $device, array $keyNames, int $startTs, int $endTs): array
    {
        try {
            $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/{$deviceId}/values/timeseries", [
                'keys'    => $keys,
                'startTs' => $startTs,
                'interval' => $endTs,
                'limit'   => 100,
                'useStrictDataTypes' => false
            ]);

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

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

            $telemetry = $response->json();

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

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

            return $telemetry;
        } catch (\Exception $e) {
            Log::error("Unexpected error in getTelemetryData", [
                'device_id' => $device->id,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            return ['error' => 'An unexpected error occurred while fetching telemetry data'];
        }
    }


    public function filterAlarm(array $data)
    {
        $token = $this->getToken();

        $deviceId = null;

        if (!empty($data['deviceId'])) {
            $deviceId = $data['deviceId'];
        } elseif (!empty($data['assetId'])) {
            $deviceId = Device::where('asset_id', $data['assetId'])->value('id');
        }

        if (!empty($data['assetId']) && empty($deviceId)) {
            return [
                'data'          => [],
                'totalPages'    => 0,
                'totalElements' => 0,
                'hasNext'       => false,
            ];
        }

        $queryParams = array_filter([
            'severityList'  => $data['severity'] ?? null,
            'assigneeId'    => $data['assignId'] ?? null,
            'pageSize'      => $data['pageSize'] ?? 10,
            'page'          => $data['page'] ?? 1,
            'startTime'     => $data['startTs'] ?? null,
            'endTime'       => $data['endTs'] ?? null,
            'deviceId'      => $deviceId,
        ], function ($value) {
            return $value !== null;
        });

        $url = "{$this->baseUrl}api/v2/alarms" . (count($queryParams) ? '?' . http_build_query($queryParams) : '');

        $response = Http::withHeaders([
            'Authorization' => "Bearer $token",
            'Accept'        => 'application/json',
        ])->get($url);

        if (!$response->successful()) {
            Log::error("API Error Response:", ['body' => $response->body()]);
            throw new Exception('API Error: ' . $response->body());
        }

        $responseData = $response->json();

        // If device filtering was applied, refine the results manually
        if (!empty($deviceId) && isset($responseData['data'])) {
            $filteredData = array_values(array_filter(
                $responseData['data'],
                function ($alarm) use ($deviceId) {
                    return isset($alarm['originator']['id']) && $alarm['originator']['id'] === $deviceId;
                }
            ));

            // Update response with the filtered data
            $responseData['data'] = $filteredData;
            $responseData['totalElements'] = count($filteredData);
        }

        return $responseData;
    }



    public function createOrUpdateAlarm(array $data)
    {

        $token = $this->getToken();

        $payload = [
            'type'       => $data['type'] ?? null,
            'severity'       => $data['severity'] ?? null,
            'acknowledged'      => false,
            'cleared'    => $data['cleared'] ?? Carbon::now()->timestamp,
            'startTs'    => $data['startTs'] ?? Carbon::now()->timestamp,
            'endTs'    => $data['endTs'] ?? Carbon::now()->timestamp,
            'originator' => [
                'id' => $data['originator'] ?? null,
                'entityType' => 'DEVICE'
            ],
            // 'assigneeId' => [
            //     'id' => $data['assigneeId'] ?? null,
            //     'entityType' => 'USER'
            // ],
            'details' => $data['details'] ?? [],
            'propagate'    => $data['propagate'] ?? false,
            'propagateToOwner'    => $data['propagateToOwner'] ?? false,

        ];


        // Optional fields
        if (!empty($data['id'])) {
            $payload['id'] = [
                'id' => $data['id'],
                'entityType' => 'ALARM'
            ];
        }



        $url = "{$this->baseUrl}api/alarm";
        $method = 'post';

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

        if (!$response->successful()) {
            Log::error("API Error Response:", ['body' => $response->body()]);
            throw new Exception('API Error: ' . $response->body());
        }

        $apiResponse = $response->json();

        return $apiResponse;
    }


    // public function deleteDevice(array $data)
    // {
    //     $token = $this->getToken();


    //     $url = "{$this->baseUrl}/api/device/{$data['deviceId']}";

    //     $response = Http::withHeaders([
    //         'Authorization' => "Bearer $token",
    //         'Accept' => 'application/json',
    //     ])->delete($url);



    //     // If response body is empty, assume success
    //     if ($response->status() === 200 && empty($response->body())) {
    //         return ['message' => 'Device deleted successfully'];
    //     }

    //     if ($response->successful()) {
    //         return $response->json();
    //     } else {
    //         throw new Exception('Failed to create Device: ' . $response->body());
    //         Log::info('API Response:', ['response' => $response]);
    //     }

    //     throw new Exception('Failed to create user: ' . $response->body());
    // }
}
