<?php

declare(strict_types=1);

namespace App\Integrations;

use Exception;

/**
 * Integração com API do Itaú - Cobrança Registrada
 * Documentação: https://developer.itau.com.br/api-cobranca-registrada
 */
class BancoItau
{
    private string $clientId;
    private string $clientSecret;
    private string $numeroAgencia;
    private string $numeroConta;
    private string $digitoConta;
    private bool $isProducao;
    private ?string $certificadoPath = null;
    private ?string $chavePrivadaPath = null;
    private ?string $certificadoSenha = null;

    /**
     * URLs da API - Itaú
     * Sandbox: https://devportal.itau.com.br/api-cobranca-registrada
     * Produção: https://api.itau.com.br/cobranca_registrada
     */
    private const URL_TOKEN_SANDBOX = 'https://sts.itau.com.br/oauth/token';
    private const URL_TOKEN_PRODUCAO = 'https://sts.itau.com.br/oauth/token';

    private const URL_COBRANCA_SANDBOX = 'https://devportal.itau.com.br/api/cobranca_registrada/v2/cobrancas';
    private const URL_COBRANCA_PRODUCAO = 'https://api.itau.com.br/cobranca_registrada/v2/cobrancas';

    public function __construct(
        string $clientId,
        string $clientSecret,
        string $numeroAgencia,
        string $numeroConta,
        string $digitoConta,
        bool $isProducao = false,
        ?string $certificadoPath = null,
        ?string $chavePrivadaPath = null,
        ?string $certificadoSenha = null
    ) {
        $this->clientId = $clientId;
        $this->clientSecret = $clientSecret;
        $this->numeroAgencia = $numeroAgencia;
        $this->numeroConta = $numeroConta;
        $this->digitoConta = $digitoConta;
        $this->isProducao = $isProducao;
        $this->certificadoPath = $certificadoPath;
        $this->chavePrivadaPath = $chavePrivadaPath;
        $this->certificadoSenha = $certificadoSenha;
    }

    /**
     * Obter token de acesso OAuth 2.0
     */
    public function getAccessToken(): string
    {
        $url = $this->isProducao ? self::URL_TOKEN_PRODUCAO : self::URL_TOKEN_SANDBOX;

        $ch = curl_init();

        $curlOptions = [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/x-www-form-urlencoded'
            ],
            CURLOPT_POSTFIELDS => http_build_query([
                'grant_type' => 'client_credentials',
                'client_id' => $this->clientId,
                'client_secret' => $this->clientSecret,
                'scope' => 'cobranca.registrada'
            ]),
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2
        ];

        // Configuração de certificado se fornecido
        if ($this->certificadoPath && $this->chavePrivadaPath) {
            if (file_exists($this->certificadoPath)) {
                $curlOptions[CURLOPT_SSLCERT] = $this->certificadoPath;
                error_log("Itaú: Usando certificado: {$this->certificadoPath}");
            } else {
                throw new Exception("Certificado digital não encontrado: {$this->certificadoPath}");
            }

            if (file_exists($this->chavePrivadaPath)) {
                $curlOptions[CURLOPT_SSLKEY] = $this->chavePrivadaPath;

                if (!empty($this->certificadoSenha)) {
                    $curlOptions[CURLOPT_SSLKEYPASSWD] = $this->certificadoSenha;
                }
            } else {
                throw new Exception("Chave privada não encontrada: {$this->chavePrivadaPath}");
            }
        }

        // CA Bundle
        $cacertPath = null;
        $possiblePaths = [
            'C:/xampp/apache/bin/curl-ca-bundle.crt',
            'C:/xampp/php/extras/ssl/cacert.pem',
            dirname(__DIR__, 2) . '/storage/cacert.pem',
        ];

        foreach ($possiblePaths as $path) {
            if (file_exists($path)) {
                $cacertPath = $path;
                break;
            }
        }

        if ($cacertPath) {
            $curlOptions[CURLOPT_CAINFO] = $cacertPath;
        } else {
            $curlOptions[CURLOPT_SSL_VERIFYPEER] = false;
            $curlOptions[CURLOPT_SSL_VERIFYHOST] = 0;
        }

        curl_setopt_array($ch, $curlOptions);

        $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 com Itaú: {$error}");
        }

        if ($httpCode !== 200) {
            $errorData = json_decode($response, true);
            $errorMsg = $errorData['error_description'] ?? $errorData['message'] ?? $errorData['error'] ?? 'Erro desconhecido';

            error_log("Itaú - Erro ao obter token:");
            error_log("  HTTP Code: {$httpCode}");
            error_log("  Response: {$response}");

            throw new Exception("Erro ao obter token (HTTP {$httpCode}): {$errorMsg}");
        }

        $data = json_decode($response, true);

        if (!isset($data['access_token'])) {
            throw new Exception("Token não retornado pela API");
        }

        return $data['access_token'];
    }

    /**
     * Criar boleto/cobrança
     *
     * @param array $dados Dados da cobrança
     * @return array Dados do boleto criado
     */
    public function criarCobranca(array $dados): array
    {
        $token = $this->getAccessToken();
        $url = $this->isProducao ? self::URL_COBRANCA_PRODUCAO : self::URL_COBRANCA_SANDBOX;

        // Processar documento do pagador
        $documento = preg_replace('/\D/', '', $dados['pagador']['documento'] ?? '');
        $tipoPessoa = strlen($documento) === 11 ? 'F' : 'J';

        // Processar telefone
        $telefoneCompleto = preg_replace('/\D/', '', $dados['pagador']['telefone'] ?? '');
        $ddd = '';
        $telefone = '';

        if (strlen($telefoneCompleto) >= 10) {
            $ddd = substr($telefoneCompleto, 0, 2);
            $telefone = substr($telefoneCompleto, 2);
        } else {
            $telefone = $telefoneCompleto;
        }

        // Montar payload conforme documentação do Itaú
        $payload = [
            'numeroAgencia' => $this->numeroAgencia,
            'numeroContaCorrente' => $this->numeroConta,
            'digitoContaCorrente' => $this->digitoConta,
            'tipoTitulo' => 'DM', // Duplicata Mercantil
            'numeroTituloBeneficiario' => $dados['numero_documento'] ?? '',
            'dataEmissao' => date('Y-m-d'),
            'dataVencimento' => $dados['data_vencimento'], // Formato: YYYY-MM-DD
            'valorOriginal' => (float)$dados['valor'],
            'valorAbatimento' => 0.00,
            'quantidadeDiasProtesto' => 0,
            'quantidadeDiasNegativacao' => 0,
            'indicadorAceiteTituloVencido' => 'N',
            'numeroDiasLimiteRecebimento' => 0,
            'codigoMoeda' => '09', // Real
            'pagador' => [
                'numeroCpfCnpj' => $documento,
                'tipoPessoa' => $tipoPessoa,
                'nome' => $dados['pagador']['nome'] ?? '',
                'endereco' => $dados['pagador']['endereco'] ?? '',
                'cidade' => $dados['pagador']['cidade'] ?? '',
                'uf' => $dados['pagador']['uf'] ?? '',
                'cep' => preg_replace('/\D/', '', $dados['pagador']['cep'] ?? ''),
                'email' => $dados['pagador']['email'] ?? '',
                'ddd' => $ddd,
                'telefone' => $telefone
            ],
            'desconto' => [
                'tipoDesconto' => 'SEM_DESCONTO',
                'dataDesconto' => '',
                'valorDesconto' => 0.00,
                'percentualDesconto' => 0.00
            ],
            'segundoDesconto' => [
                'dataDesconto' => '',
                'valorDesconto' => 0.00,
                'percentualDesconto' => 0.00
            ],
            'terceiroDesconto' => [
                'dataDesconto' => '',
                'valorDesconto' => 0.00,
                'percentualDesconto' => 0.00
            ],
            'multa' => [
                'tipoMulta' => 'SEM_MULTA',
                'dataMulta' => '',
                'valorMulta' => 0.00,
                'percentualMulta' => 0.00
            ],
            'juros' => [
                'tipoJuros' => 'VALOR_POR_DIA',
                'dataJuros' => '',
                'valorJuros' => 0.00,
                'percentualJuros' => 0.00
            ]
        ];

        // Adicionar multa se informada
        if (!empty($dados['multa'])) {
            $payload['multa'] = [
                'tipoMulta' => 'PERCENTUAL',
                'dataMulta' => $dados['data_vencimento'],
                'valorMulta' => 0.00,
                'percentualMulta' => (float)$dados['multa']['percentual']
            ];
        }

        // Adicionar juros se informado
        if (!empty($dados['juros'])) {
            $payload['juros'] = [
                'tipoJuros' => 'PERCENTUAL',
                'dataJuros' => $dados['data_vencimento'],
                'valorJuros' => 0.00,
                'percentualJuros' => (float)$dados['juros']['percentual']
            ];
        }

        // Adicionar desconto se informado
        if (!empty($dados['desconto'])) {
            $payload['desconto'] = [
                'tipoDesconto' => 'PERCENTUAL',
                'dataDesconto' => $dados['desconto']['data_limite'] ?? $dados['data_vencimento'],
                'valorDesconto' => 0.00,
                'percentualDesconto' => (float)$dados['desconto']['percentual']
            ];
        }

        error_log("Itaú - Payload da cobrança: " . json_encode($payload, JSON_PRETTY_PRINT));

        $ch = curl_init();

        $headers = [
            'Content-Type: application/json',
            'Authorization: Bearer ' . $token,
            'x-itau-flowID: ' . uniqid('flow_', true),
            'x-itau-correlationID: ' . uniqid('corr_', true)
        ];

        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_POSTFIELDS => json_encode($payload),
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false
        ]);

        // Adicionar certificado se fornecido
        if ($this->certificadoPath && file_exists($this->certificadoPath)) {
            curl_setopt($ch, CURLOPT_SSLCERT, $this->certificadoPath);
        }
        if ($this->chavePrivadaPath && file_exists($this->chavePrivadaPath)) {
            curl_setopt($ch, CURLOPT_SSLKEY, $this->chavePrivadaPath);
            if (!empty($this->certificadoSenha)) {
                curl_setopt($ch, CURLOPT_SSLKEYPASSWD, $this->certificadoSenha);
            }
        }

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

        if ($error) {
            error_log("Itaú - Erro cURL ao criar cobrança: {$error}");
            throw new Exception("Erro ao criar cobrança: {$error}");
        }

        if ($httpCode !== 200 && $httpCode !== 201) {
            $errorData = json_decode($response, true);
            $errorMsg = $errorData['message'] ?? $errorData['title'] ?? $errorData['error'] ?? 'Erro desconhecido';

            error_log("Itaú - Erro na criação da cobrança:");
            error_log("  HTTP Code: {$httpCode}");
            error_log("  Response: " . $response);

            throw new Exception("Erro ao criar cobrança (HTTP {$httpCode}): {$errorMsg}");
        }

        $boleto = json_decode($response, true);

        return [
            'nosso_numero' => $boleto['nossoNumero'] ?? '',
            'codigo_barras' => $boleto['codigoBarras'] ?? '',
            'linha_digitavel' => $boleto['linhaDigitavel'] ?? '',
            'pdf_url' => $boleto['urlPdf'] ?? '',
            'qrcode' => $boleto['qrCode'] ?? '',
            'status' => 'REGISTRADO'
        ];
    }

    /**
     * Consultar boleto pelo nosso número
     */
    public function consultarCobranca(string $nossoNumero): array
    {
        $token = $this->getAccessToken();
        $url = ($this->isProducao ? self::URL_COBRANCA_PRODUCAO : self::URL_COBRANCA_SANDBOX) . "/{$nossoNumero}";

        $ch = curl_init();

        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $token,
                'x-itau-flowID: ' . uniqid('flow_', true),
                'x-itau-correlationID: ' . uniqid('corr_', true)
            ],
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false
        ]);

        if ($this->certificadoPath && file_exists($this->certificadoPath)) {
            curl_setopt($ch, CURLOPT_SSLCERT, $this->certificadoPath);
        }
        if ($this->chavePrivadaPath && file_exists($this->chavePrivadaPath)) {
            curl_setopt($ch, CURLOPT_SSLKEY, $this->chavePrivadaPath);
            if (!empty($this->certificadoSenha)) {
                curl_setopt($ch, CURLOPT_SSLKEYPASSWD, $this->certificadoSenha);
            }
        }

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

        if ($httpCode !== 200) {
            throw new Exception("Erro ao consultar cobrança (HTTP {$httpCode})");
        }

        return json_decode($response, true) ?: [];
    }

    /**
     * Cancelar boleto
     */
    public function cancelarCobranca(string $nossoNumero, string $motivoCancelamento = 'ACERTOS'): bool
    {
        $token = $this->getAccessToken();
        $url = ($this->isProducao ? self::URL_COBRANCA_PRODUCAO : self::URL_COBRANCA_SANDBOX) . "/{$nossoNumero}/cancelar";

        $ch = curl_init();

        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'Authorization: Bearer ' . $token,
                'x-itau-flowID: ' . uniqid('flow_', true),
                'x-itau-correlationID: ' . uniqid('corr_', true)
            ],
            CURLOPT_POSTFIELDS => json_encode([
                'motivoCancelamento' => $motivoCancelamento
            ]),
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false
        ]);

        if ($this->certificadoPath && file_exists($this->certificadoPath)) {
            curl_setopt($ch, CURLOPT_SSLCERT, $this->certificadoPath);
        }
        if ($this->chavePrivadaPath && file_exists($this->chavePrivadaPath)) {
            curl_setopt($ch, CURLOPT_SSLKEY, $this->chavePrivadaPath);
            if (!empty($this->certificadoSenha)) {
                curl_setopt($ch, CURLOPT_SSLKEYPASSWD, $this->certificadoSenha);
            }
        }

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

        return $httpCode === 204 || $httpCode === 200;
    }

    /**
     * Obter PDF do boleto
     */
    public function obterPdfBoleto(string $nossoNumero): ?string
    {
        $token = $this->getAccessToken();
        $url = ($this->isProducao ? self::URL_COBRANCA_PRODUCAO : self::URL_COBRANCA_SANDBOX) . "/{$nossoNumero}/pdf";

        $ch = curl_init();

        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $token,
                'x-itau-flowID: ' . uniqid('flow_', true),
                'x-itau-correlationID: ' . uniqid('corr_', true)
            ],
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false
        ]);

        if ($this->certificadoPath && file_exists($this->certificadoPath)) {
            curl_setopt($ch, CURLOPT_SSLCERT, $this->certificadoPath);
        }
        if ($this->chavePrivadaPath && file_exists($this->chavePrivadaPath)) {
            curl_setopt($ch, CURLOPT_SSLKEY, $this->chavePrivadaPath);
            if (!empty($this->certificadoSenha)) {
                curl_setopt($ch, CURLOPT_SSLKEYPASSWD, $this->certificadoSenha);
            }
        }

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
        curl_close($ch);

        if ($httpCode === 200) {
            if (strpos($contentType, 'application/pdf') !== false) {
                return base64_encode($response);
            }

            if (strpos($contentType, 'application/json') !== false) {
                $dados = json_decode($response, true);
                if (isset($dados['pdf'])) {
                    return $dados['pdf'];
                }
            }
        }

        return null;
    }
}

