<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log; // Importa el Facade de Log
use Carbon\Carbon;
use Illuminate\Http\Client\RequestException; // Importar esta clase para try-catch

class AmpecoApiService
{
    protected $baseUrl;
    protected $token;

    public function __construct()
    {
        $this->baseUrl = rtrim(config('services.ampeco.url'), '/');
        $this->token = config('services.ampeco.token');
    }

    protected function getHeaders()
    {
        return [
            'Authorization' => 'Bearer ' . $this->token,
            'Accept' => 'application/json',
        ];
    }

    /**
     * Obtiene una lista de usuarios de la API. (URL: v1.0)
     *
     * @param int|null $groupId Filtro por ID de grupo.
     * @param array $filters Filtros adicionales como 'search', 'page', 'per_page', 'sort'.
     * @return array
     */
    public function getUsers($groupId = null, $filters = [])
    {
        $cacheKey = 'ampeco.users' . ($groupId ? '.group.' . $groupId : '') . '.' . md5(json_encode($filters));

        return Cache::remember($cacheKey, now()->addMinute(1), function () use ($groupId, $filters) { // CACHE A 1 MINUTO PARA DEPURAR
            $queryParams = [];

            if ($groupId !== null && $groupId !== '') {
                $queryParams['filter[userGroupId]'] = $groupId;
            }

            if (isset($filters['search']) && !empty($filters['search'])) {
                $queryParams['filter[search]'] = $filters['search'];
            }

            $queryParams['include'] = ['userGroups'];
            
            $queryParams['per_page'] = $filters['per_page'] ?? 50; 
            if (isset($filters['page'])) {
                $queryParams['page'] = $filters['page'];
            }
            if (isset($filters['sort'])) {
                $queryParams['sort'] = $filters['sort'];
            }

            $url = "{$this->baseUrl}/users/v1.0"; // URL v1.0

            Log::info("AmpecoApiService: Requesting users from API.", ['full_url' => $url . '?' . http_build_query($queryParams), 'headers' => $this->getHeaders()]); // LOG DE LA PETICIÓN

            try {
                $response = Http::withHeaders($this->getHeaders())
                                ->timeout(60)
                                ->retry(3, 1000)
                                // Eliminamos withoutThrowing() y manejamos la excepción directamente
                                ->get($url, $queryParams);

                Log::info("AmpecoApiService: API Response for users.", ['status' => $response->status(), 'body_sample' => substr($response->body(), 0, 500) . '...', 'meta_data' => $response->json()['meta'] ?? 'N/A']); // LOG DE LA RESPUESTA

                if ($response->successful()) {
                    return $response->json();
                }
                // Si no es successful, logueamos el error sin lanzar excepción
                Log::error("AmpecoApiService: Failed to fetch users. Status: " . $response->status(), ['url' => $url, 'body' => $response->body()]);
            } catch (RequestException $e) { // Captura excepciones HTTP (4xx, 5xx)
                Log::error("AmpecoApiService: RequestException for users: " . $e->getMessage(), ['url' => $url, 'status' => $e->response->status() ?? 'N/A']);
            } catch (\Exception $e) { // Captura cualquier otra excepción general (ej. cURL error)
                Log::error("AmpecoApiService: General error for users: " . $e->getMessage(), ['url' => $url]);
            }
            return []; // Retorna vacío para que el comando pueda seguir
        });
    }

    /**
     * Obtiene un usuario por su ID de la API. (URL: v1.0)
     *
     * @param int $userId
     * @return array|null
     */
    public function getUserById($userId)
    {
        $cacheKey = 'ampeco.user.' . $userId;

        return Cache::remember($cacheKey, now()->addHour(), function () use ($userId) {
            $url = "{$this->baseUrl}/users/v1.0/{$userId}"; // URL v1.0
            try {
                $response = Http::withHeaders($this->getHeaders())
                                ->timeout(60)
                                ->retry(3, 1000)
                                // Eliminamos withoutThrowing()
                                ->get($url);

                if ($response->successful()) {
                    return $response->json()['data'] ?? null;
                }
                Log::error("AmpecoApiService: Failed to fetch user by ID {$userId}. Status: " . $response->status(), ['url' => $url, 'body' => $response->body()]);
            } catch (RequestException $e) {
                Log::error("AmpecoApiService: RequestException for user by ID: " . $e->getMessage(), ['url' => $url, 'status' => $e->response->status() ?? 'N/A']);
            } catch (\Exception $e) {
                Log::error("AmpecoApiService: General error for user by ID: " . $e->getMessage(), ['url' => $url]);
            }
            return null;
        });
    }

    /**
     * Obtiene las sesiones de un usuario desde la API, manejando la paginación y el ordenamiento. (URL: v1.0)
     * Este método NO acumula todo en memoria. Devuelve cada página.
     * El llamador debe iterar por las páginas.
     *
     * @param int $userId El ID del usuario de la API.
     * @param array $filters Filtros adicionales para la API (ej. 'filter[startedAt][$gte]', 'filter[startedAt][$lte]', 'filter[startedAfter]').
     * @param int $page La página actual a solicitar.
     * @param int $perPage Cuántos elementos por página.
     * @return array {'data': [], 'meta': {}}
     */
    public function getSessionsPage($userId, $filters = [], $page = 1, $perPage = 50)
    {
        $queryParams = [
            'filter[userId]' => $userId,
            'filter[status]' => 'finished',
            'per_page' => $perPage,
            'page' => $page,
            'sort' => '-startedAt', // Usamos startedAt para ordenar
        ];

        // Añadir filtro filter[startedAfter]
        if (isset($filters['filter[startedAfter]'])) {
            $queryParams['filter[startedAfter]'] = $filters['filter[startedAfter]'];
        }
        // También mantener los filtros de rango startedAt si se usan
        if (isset($filters['filter[startedAt][$gte]'])) {
            $queryParams['filter[startedAt][$gte]'] = $filters['filter[startedAt][$gte]'];
        }
        if (isset($filters['filter[startedAt][$lte]'])) {
            $queryParams['filter[startedAt][$lte]'] = $filters['filter[startedAt][$lte]'];
        }

        $url = "{$this->baseUrl}/sessions/v1.0"; // URL v1.0
        try {
            $response = Http::withHeaders($this->getHeaders())
                            ->timeout(60)
                            ->retry(3, 1000)
                            // Eliminamos withoutThrowing()
                            ->get($url, $queryParams);

            if ($response->successful()) {
                return $response->json();
            }
            Log::error("AmpecoApiService: Failed to fetch sessions page {$page} for user {$userId}. Status: " . $response->status(), ['url' => $url, 'body' => $response->body(), 'query_params' => $queryParams]);
        } catch (RequestException $e) {
            Log::error("AmpecoApiService: RequestException for sessions: " . $e->getMessage(), ['url' => $url, 'status' => $e->response->status() ?? 'N/A']);
        } catch (\Exception $e) {
            Log::error("AmpecoApiService: General error for sessions: " . $e->getMessage(), ['url' => $url]);
        }
        return ['data' => [], 'meta' => []];
    }

    /**
     * Obtiene recibos de la API. (URL: v2.0)
     *
     * @param array $filters Filtros adicionales.
     * @return array
     */
    public function getReceipts($filters = [])
    {
        $cacheKey = 'ampeco.receipts.' . md5(json_encode($filters));
        
        return Cache::remember($cacheKey, now()->addHour(), function () use ($filters) {
            $url = "{$this->baseUrl}/receipts/v2.0"; // URL v2.0
            try {
                $response = Http::withHeaders($this->getHeaders())
                                ->timeout(60)
                                ->retry(3, 1000)
                                // Eliminamos withoutThrowing()
                                ->get($url, $filters);

                if ($response->successful()) {
                    return $response->json()['data'] ?? [];
                }
                Log::error("AmpecoApiService: Failed to fetch receipts. Status: " . $response->status(), ['url' => $url, 'body' => $response->body()]);
            } catch (RequestException $e) {
                Log::error("AmpecoApiService: RequestException for receipts: " . $e->getMessage(), ['url' => $url, 'status' => $e->response->status() ?? 'N/A']);
            } catch (\Exception $e) {
                Log::error("AmpecoApiService: General error for receipts: " . $e->getMessage(), ['url' => $url]);
            }
            return [];
        });
    }
    
    /**
     * Convierte vatios-hora (Wh) a kilovatios-hora (kWh).
     *
     * @param float $wh Valor en vatios-hora.
     * @return float Valor en kilovatios-hora.
     */
    public function convertToKwh($wh)
    {
        return (float)$wh / 1000;
    }

    /**
     * Obtiene la lista de grupos de usuarios desde la API. (URL: v1.0)
     *
     * @return array
     */
    public function getUserGroups()
    {
        $cacheKey = 'ampeco.user.groups';
        
        return Cache::remember($cacheKey, now()->addDay(), function () {
            $url = "{$this->baseUrl}/user-groups/v1.0"; // URL v1.0
            try {
                $response = Http::withHeaders($this->getHeaders())
                                ->timeout(60)
                                ->retry(3, 1000)
                                // Eliminamos withoutThrowing()
                                ->get($url);

                if ($response->successful()) {
                    return $response->json()['data'] ?? [];
                }
                Log::error("AmpecoApiService: Failed to fetch user groups. Status: " . $response->status(), ['url' => $url, 'body' => $response->body()]);
            } catch (RequestException $e) {
                Log::error("AmpecoApiService: RequestException for user groups: " . $e->getMessage(), ['url' => $url, 'status' => $e->response->status() ?? 'N/A']);
            } catch (\Exception $e) {
                Log::error("AmpecoApiService: General error for user groups: " . $e->getMessage(), ['url' => $url]);
            }
            return [];
        });
    }

    /**
     * Obtiene un grupo de usuarios por su ID de la API. (URL: v1.0)
     *
     * @param int $groupId
     * @return array|null
     */
    public function getUserGroupById($groupId)
    {
        $cacheKey = 'ampeco.user.group.' . $groupId;
        
        return Cache::remember($cacheKey, now()->addDay(), function () use ($groupId) {
            $url = "{$this->baseUrl}/user-groups/v1.0/{$groupId}"; // URL v1.0
            try {
                $response = Http::withHeaders($this->getHeaders())
                                ->timeout(60)
                                ->retry(3, 1000)
                                // Eliminamos withoutThrowing()
                                ->get($url);

                if ($response->successful()) {
                    return $response->json()['data'] ?? null;
                }
                Log::error("AmpecoApiService: Failed to fetch user group by ID {$groupId}. Status: " . $response->status(), ['url' => $url, 'body' => $response->body()]);
            } catch (RequestException $e) {
                Log::error("AmpecoApiService: RequestException for user group by ID: " . $e->getMessage(), ['url' => $url, 'status' => $e->response->status() ?? 'N/A']);
            } catch (\Exception $e) {
                Log::error("AmpecoApiService: General error for user group by ID: " . $e->getMessage(), ['url' => $url]);
            }
            return null;
        });
    }

    /**
     * Obtiene un punto de carga por su ID de la API. (URL: v2.0/{id})
     * Retorna el item si es exitoso (array), o null si no encontrado/error.
     * No lanza excepción si es 403.
     *
     * @param int $chargePointId El ID del punto de carga de la API.
     * @return array|null
     */
    public function getChargePointById($chargePointId)
    {
        $cacheKey = 'ampeco.charge_point.' . $chargePointId;
        return Cache::remember($cacheKey, now()->addDay(), function () use ($chargePointId) {
            $url = "{$this->baseUrl}/charge-points/v2.0/{$chargePointId}";
            
            try {
                $response = Http::withHeaders($this->getHeaders())
                                ->timeout(60)
                                ->retry(3, 1000)
                                // Eliminamos withoutThrowing()
                                ->get($url);

                if ($response->successful()) {
                    return $response->json()['data'] ?? null;
                }
                
                // Si no es successful, logueamos la advertencia sin lanzar excepción
                Log::warning("AmpecoApiService: Charge Point ID {$chargePointId} returned status {$response->status()} (Access Denied/Not Found/Other Error).");
            } catch (RequestException $e) { // Captura si Guzzle/Laravel lanza una excepción específica de request
                Log::error("AmpecoApiService: RequestException for CP ID {$chargePointId}: " . $e->getMessage(), ['url' => $url, 'status' => $e->response->status() ?? 'N/A']);
            } catch (\Exception $e) { // Captura cualquier otra excepción general
                Log::error("AmpecoApiService: General error fetching CP ID {$chargePointId}: " . $e->getMessage(), ['url' => $url]);
            }
            
            return null; // Retorna null para cualquier fallo (403, 404, 500, cURL error)
        });
    }

    /**
     * Obtiene una ubicación por su ID de la API. (URL: v2.0/{id})
     * Retorna el item si es exitoso (array), o null si no encontrado/error.
     * No lanza excepción si es 403.
     *
     * @param int $locationId El ID de la ubicación de la API.
     * @return array|null
     */
    public function getLocationById($locationId)
    {
        $cacheKey = 'ampeco.location.' . $locationId;
        return Cache::remember($cacheKey, now()->addDay(), function () use ($locationId) {
            $url = "{$this->baseUrl}/locations/v2.0/{$locationId}";
            
            try {
                $response = Http::withHeaders($this->getHeaders())
                                ->timeout(60)
                                ->retry(3, 1000)
                                // Eliminamos withoutThrowing()
                                ->get($url);

                if ($response->successful()) {
                    return $response->json()['data'] ?? null;
                }

                Log::warning("AmpecoApiService: Location ID {$locationId} returned status {$response->status()} (Access Denied/Not Found/Other Error).");
            } catch (RequestException $e) {
                Log::error("AmpecoApiService: RequestException for Location ID {$locationId}: " . $e->getMessage(), ['url' => $url, 'status' => $e->response->status() ?? 'N/A']);
            } catch (\Exception $e) {
                Log::error("AmpecoApiService: General error for Location ID {$locationId}: " . $e->getMessage(), ['url' => $url]);
            }
            
            return null;
        });
    }

    /**
     * Obtiene una sesión específica por su ID de la API. (URL: v1.0/{id})
     * Retorna el item si es exitoso (array), o null si no encontrado/error.
     *
     * @param int $sessionId El ID de la sesión de la API.
     * @return array|null
     */
    public function getSessionById($sessionId)
    {
        $cacheKey = 'ampeco.session.' . $sessionId;
        return Cache::remember($cacheKey, now()->addHour(), function () use ($sessionId) {
            $url = "{$this->baseUrl}/sessions/v1.0/{$sessionId}";
            
            try {
                $response = Http::withHeaders($this->getHeaders())
                                ->timeout(60)
                                ->retry(3, 1000)
                                ->get($url);

                if ($response->successful()) {
                    return $response->json()['data'] ?? null;
                }
                
                Log::warning("AmpecoApiService: Session ID {$sessionId} returned status {$response->status()} (Access Denied/Not Found/Other Error).");
            } catch (RequestException $e) {
                Log::error("AmpecoApiService: RequestException for Session ID {$sessionId}: " . $e->getMessage(), ['url' => $url, 'status' => $e->response->status() ?? 'N/A']);
            } catch (\Exception $e) {
                Log::error("AmpecoApiService: General error for Session ID {$sessionId}: " . $e->getMessage(), ['url' => $url]);
            }
            
            return null;
        });
    }

    /**
     * Obtiene un operador de roaming por su ID de la API. (URL: v2.0/{id})
     * Retorna el item si es exitoso (array), o null si no encontrado/error.
     *
     * @param int $roamingOperatorId El ID del operador de roaming de la API.
     * @return array|null
     */
    public function getRoamingOperatorById($roamingOperatorId)
    {
        $cacheKey = 'ampeco.roaming_operator.' . $roamingOperatorId;
        return Cache::remember($cacheKey, now()->addDay(), function () use ($roamingOperatorId) {
            $url = "{$this->baseUrl}/roaming-operators/v2.0/{$roamingOperatorId}";
            
            try {
                $response = Http::withHeaders($this->getHeaders())
                                ->timeout(60)
                                ->retry(3, 1000)
                                ->get($url);

                if ($response->successful()) {
                    return $response->json()['data'] ?? null;
                }

                Log::warning("AmpecoApiService: Roaming Operator ID {$roamingOperatorId} returned status {$response->status()} (Access Denied/Not Found/Other Error).");
            } catch (RequestException $e) {
                Log::error("AmpecoApiService: RequestException for Roaming Operator ID {$roamingOperatorId}: " . $e->getMessage(), ['url' => $url, 'status' => $e->response->status() ?? 'N/A']);
            } catch (\Exception $e) {
                Log::error("AmpecoApiService: General error for Roaming Operator ID {$roamingOperatorId}: " . $e->getMessage(), ['url' => $url]);
            }
            
            return null;
        });
    }

    /**
     * Obtiene el business name del operador de roaming para una sesión específica.
     * Combina getSessionById y getRoamingOperatorById para obtener el business name.
     *
     * @param int $sessionId El ID de la sesión de la API.
     * @return string|null El business name o null si no se puede obtener.
     */
    public function getRoamingBusinessNameForSession($sessionId)
    {
        $cacheKey = 'ampeco.session_roaming_business.' . $sessionId;
        return Cache::remember($cacheKey, now()->addHour(), function () use ($sessionId) {
            try {
                // Paso 1: Obtener la sesión para obtener el roamingOperatorCpoId
                $session = $this->getSessionById($sessionId);
                
                if (!$session || !isset($session['roamingOperatorCpoId'])) {
                    Log::info("AmpecoApiService: No roaming operator found for session {$sessionId}");
                    return null;
                }

                $roamingOperatorId = $session['roamingOperatorCpoId'];
                
                // Paso 2: Obtener el operador de roaming para obtener el business name
                $roamingOperator = $this->getRoamingOperatorById($roamingOperatorId);
                
                if (!$roamingOperator || !isset($roamingOperator['businessName'])) {
                    Log::info("AmpecoApiService: No business name found for roaming operator {$roamingOperatorId}");
                    return null;
                }

                return $roamingOperator['businessName'];
                
            } catch (\Exception $e) {
                Log::error("AmpecoApiService: Error getting roaming business name for session {$sessionId}: " . $e->getMessage());
                return null;
            }
        });
    }
}