<?php

declare(strict_types=1);

namespace App\Services\NFSe;

use Exception;

/**
 * Service para autenticação OAuth2 no Portal Nacional de NFS-e
 */
class NFSeNacionalAuthService
{
    private string $baseUrl;
    private string $clientId;
    private string $clientSecret;
    private ?string $accessToken = null;
    private ?int $tokenExpiresAt = null;

    public function __construct(string $clientId, string $clientSecret, bool $homologacao = false)
    {
        $this->clientId = $clientId;
        $this->clientSecret = $clientSecret;
        $this->baseUrl = $homologacao
            ? 'https://api-hml.nfse.gov.br'
            : 'https://api.nfse.gov.br';
    }

    /**
     * Obtém token de acesso OAuth2 (com cache)
     */
    public function obterToken(): string
    {
        // Se já tem token válido, retorna
        if ($this->accessToken && $this->tokenExpiresAt && $this->tokenExpiresAt > time()) {
            return $this->accessToken;
        }

        // Obter novo token
        $response = $this->solicitarToken();

        $this->accessToken = $response['access_token'] ?? null;
        $expiresIn = (int) ($response['expires_in'] ?? 3600);
        $this->tokenExpiresAt = time() + $expiresIn - 300; // -5min de margem de segurança

        if (!$this->accessToken) {
            throw new Exception('Não foi possível obter token de acesso. Verifique Client ID e Secret.');
        }

        return $this->accessToken;
    }

    /**
     * Solicita novo token OAuth2 ao servidor
     */
    private function solicitarToken(): array
    {
        if (empty($this->clientId) || empty($this->clientSecret)) {
            throw new Exception('Client ID e Client Secret são obrigatórios para autenticação OAuth2.');
        }

        $ch = curl_init($this->baseUrl . '/oauth/token');

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode([
                'grant_type' => 'client_credentials',
                'client_id' => $this->clientId,
                'client_secret' => $this->clientSecret,
            ]),
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'Accept: application/json',
            ],
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_TIMEOUT => 30,
        ]);

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

        if ($error) {
            throw new Exception("Erro ao conectar ao Portal Nacional: $error");
        }

        if ($httpCode !== 200) {
            $errorData = json_decode($response, true);
            $errorMessage = $errorData['error_description'] ?? $errorData['message'] ?? 'Erro desconhecido';
            throw new Exception("Erro ao obter token OAuth2 (HTTP $httpCode): $errorMessage");
        }

        $data = json_decode($response, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new Exception('Resposta inválida do servidor OAuth2: ' . json_last_error_msg());
        }

        return $data;
    }

    /**
     * Limpa o token em cache (força nova autenticação)
     */
    public function limparToken(): void
    {
        $this->accessToken = null;
        $this->tokenExpiresAt = null;
    }
}
