<?php
/**
 * MercadoPagoOAuth
 * 
 * Gerencia o fluxo OAuth 2.0 para Mercado Pago Connect (Marketplace)
 * Permite que lojistas conectem suas contas para receber pagamentos.
 * 
 * Credenciais OAuth são carregadas de oauth_client_id e oauth_client_secret
 */

namespace Payment;

class MercadoPagoOAuth
{
    private \PDO $db;
    private string $clientId;
    private string $clientSecret;
    private string $redirectUri;
    private string $baseUrl = 'https://api.mercadopago.com';
    private string $authUrl = 'https://auth.mercadopago.com.br/authorization';

    public function __construct(\PDO $db)
    {
        $this->db = $db;
        $this->loadCredentialsFromDatabase();
    }

    /**
     * Carrega credenciais OAuth do banco de dados (colunas oauth_client_id e oauth_client_secret)
     */
    private function loadCredentialsFromDatabase(): void
    {
        $stmt = $this->db->prepare("SELECT oauth_client_id, oauth_client_secret, oauth_redirect_uri FROM payment_gateways WHERE name = 'mercadopago' AND is_active = 1");
        $stmt->execute();
        $gateway = $stmt->fetch(\PDO::FETCH_ASSOC);

        if ($gateway) {
            $this->clientId = $gateway['oauth_client_id'] ?? '';
            $this->clientSecret = $gateway['oauth_client_secret'] ?? '';
            $this->redirectUri = $gateway['oauth_redirect_uri'] ?? 'https://dev.duolead.com.br/api/mercadopago-callback.php';
        } else {
            $this->clientId = '';
            $this->clientSecret = '';
            $this->redirectUri = 'https://dev.duolead.com.br/api/mercadopago-callback.php';
        }
    }

    /**
     * Verifica se as credenciais OAuth estão configuradas
     */
    public function hasCredentials(): bool
    {
        return !empty($this->clientId) && !empty($this->clientSecret);
    }

    /**
     * Gera a URL de autorização OAuth
     */
    public function getAuthorizationUrl(int $storeId): string
    {
        $state = bin2hex(random_bytes(32));
        
        if (session_status() !== PHP_SESSION_ACTIVE) {
            session_start();
        }
        $_SESSION['mp_oauth_state'] = $state;
        $_SESSION['mp_oauth_store_id'] = $storeId;

        $params = [
            'client_id' => $this->clientId,
            'response_type' => 'code',
            'platform_id' => 'mp',
            'state' => $state,
            'redirect_uri' => $this->redirectUri
        ];

        return $this->authUrl . '?' . http_build_query($params);
    }

    /**
     * Troca o code por access_token
     */
    public function exchangeCodeForToken(string $code): array
    {
        $data = [
            'client_id' => $this->clientId,
            'client_secret' => $this->clientSecret,
            'code' => $code,
            'grant_type' => 'authorization_code',
            'redirect_uri' => $this->redirectUri
        ];

        $response = $this->makeRequest('POST', '/oauth/token', $data);

        if (isset($response['access_token'])) {
            return [
                'success' => true,
                'access_token' => $response['access_token'],
                'refresh_token' => $response['refresh_token'] ?? null,
                'expires_in' => $response['expires_in'] ?? 21600,
                'user_id' => $response['user_id'] ?? null,
                'public_key' => $response['public_key'] ?? null,
                'live_mode' => $response['live_mode'] ?? false
            ];
        }

        return [
            'success' => false,
            'error' => $response['error'] ?? 'unknown_error',
            'message' => $response['message'] ?? 'Erro ao obter token de acesso'
        ];
    }

    /**
     * Renova o access_token usando refresh_token
     */
    public function refreshToken(string $refreshToken): array
    {
        $data = [
            'client_id' => $this->clientId,
            'client_secret' => $this->clientSecret,
            'refresh_token' => $refreshToken,
            'grant_type' => 'refresh_token'
        ];

        $response = $this->makeRequest('POST', '/oauth/token', $data);

        if (isset($response['access_token'])) {
            return [
                'success' => true,
                'access_token' => $response['access_token'],
                'refresh_token' => $response['refresh_token'] ?? $refreshToken,
                'expires_in' => $response['expires_in'] ?? 21600
            ];
        }

        return [
            'success' => false,
            'error' => $response['error'] ?? 'unknown_error'
        ];
    }

    /**
     * Salva a integração no banco de dados
     */
    public function saveIntegration(int $storeId, array $tokenData): bool
    {
        $expiresAt = date('Y-m-d H:i:s', time() + ($tokenData['expires_in'] ?? 21600));

        $sql = "INSERT INTO store_payment_integrations 
                (store_id, provider, mp_user_id, mp_access_token, mp_refresh_token, mp_public_key, mp_expires_at, connected_at, is_active)
                VALUES (?, 'mercadopago', ?, ?, ?, ?, ?, NOW(), 1)
                ON DUPLICATE KEY UPDATE
                mp_user_id = VALUES(mp_user_id),
                mp_access_token = VALUES(mp_access_token),
                mp_refresh_token = VALUES(mp_refresh_token),
                mp_public_key = VALUES(mp_public_key),
                mp_expires_at = VALUES(mp_expires_at),
                connected_at = NOW(),
                is_active = 1";

        $stmt = $this->db->prepare($sql);
        return $stmt->execute([
            $storeId,
            $tokenData['user_id'] ?? null,
            $this->encrypt($tokenData['access_token']),
            $this->encrypt($tokenData['refresh_token'] ?? ''),
            $tokenData['public_key'] ?? null,
            $expiresAt
        ]);
    }

    /**
     * Busca integração da loja
     */
    public function getIntegration(int $storeId): ?array
    {
        $stmt = $this->db->prepare("SELECT * FROM store_payment_integrations WHERE store_id = ? AND provider = 'mercadopago' AND is_active = 1");
        $stmt->execute([$storeId]);
        $integration = $stmt->fetch(\PDO::FETCH_ASSOC);

        if ($integration) {
            $integration['mp_access_token'] = $this->decrypt($integration['mp_access_token']);
            $integration['mp_refresh_token'] = $this->decrypt($integration['mp_refresh_token']);
        }

        return $integration ?: null;
    }

    /**
     * Desconecta integração
     */
    public function disconnect(int $storeId): bool
    {
        $stmt = $this->db->prepare("UPDATE store_payment_integrations SET is_active = 0 WHERE store_id = ? AND provider = 'mercadopago'");
        return $stmt->execute([$storeId]);
    }

    /**
     * Valida o state para prevenir CSRF
     */
    public function validateState(string $state): bool
    {
        if (session_status() !== PHP_SESSION_ACTIVE) {
            session_start();
        }
        return isset($_SESSION['mp_oauth_state']) && hash_equals($_SESSION['mp_oauth_state'], $state);
    }

    private function encrypt(string $data): string
    {
        if (empty($data)) return '';
        $key = $this->getEncryptionKey();
        $iv = random_bytes(16);
        $encrypted = openssl_encrypt($data, 'AES-256-CBC', $key, 0, $iv);
        return base64_encode($iv . $encrypted);
    }

    private function decrypt(string $data): string
    {
        if (empty($data)) return '';
        $key = $this->getEncryptionKey();
        $data = base64_decode($data);
        $iv = substr($data, 0, 16);
        $encrypted = substr($data, 16);
        return openssl_decrypt($encrypted, 'AES-256-CBC', $key, 0, $iv) ?: '';
    }

    private function getEncryptionKey(): string
    {
        return hash('sha256', $this->clientSecret, true);
    }

    private function makeRequest(string $method, string $endpoint, array $data = []): array
    {
        $url = $this->baseUrl . $endpoint;

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);

        $headers = ['Content-Type: application/x-www-form-urlencoded'];

        if ($method === 'POST') {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        }

        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

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

        return json_decode($response, true) ?? ['error' => 'invalid_response', 'http_code' => $httpCode];
    }
}
