<?php
/**
 * API Tokens Controller
 * Gerencia CRUD de tokens de API (DETRAN, SEFAZ, etc)
 */

namespace Controllers;

use Core\Request;
use Core\Response;
use Middleware\Auth;

class ApiTokensController
{
    /**
     * GET /api-tokens - Listar todas as APIs
     */
    public static function index(): void
    {
        Auth::requireSuperAdmin();
        
        $pdo = getDBConnection();
        $stmt = $pdo->query("
            SELECT 
                at.*,
                COUNT(DISTINCT s.id) as sites_using
            FROM api_tokens at
            LEFT JOIN sites s ON s.api_token_id = at.id
            GROUP BY at.id
            ORDER BY at.name ASC
        ");
        
        $tokens = $stmt->fetchAll();
        
        // Mascarar tokens por segurança
        foreach ($tokens as &$token) {
            if (!empty($token['token_value'])) {
                $len = strlen($token['token_value']);
                if ($len > 12) {
                    $token['token_masked'] = substr($token['token_value'], 0, 6) . '...' . substr($token['token_value'], -4);
                } else {
                    $token['token_masked'] = '***';
                }
            } else {
                $token['token_masked'] = '';
            }
            // Remover valor real do token na listagem
            unset($token['token_value']);
        }
        
        Response::success($tokens);
    }
    
    /**
     * GET /api-token?id={id} - Obter API específica (com token completo)
     */
    public static function show(): void
    {
        Auth::requireSuperAdmin();
        
        $id = (int)Request::get('id', 0);
        
        if (!$id) {
            Response::error('ID da API é obrigatório', 400);
        }
        
        $pdo = getDBConnection();
        $stmt = $pdo->prepare("
            SELECT at.*, COUNT(DISTINCT s.id) as sites_using
            FROM api_tokens at
            LEFT JOIN sites s ON s.api_token_id = at.id
            WHERE at.id = ?
            GROUP BY at.id
        ");
        $stmt->execute([$id]);
        $token = $stmt->fetch();
        
        if (!$token) {
            Response::notFound('API não encontrada');
        }
        
        // Retornar dados incluindo o token completo (só super admin vê)
        Response::success($token);
    }
    
    /**
     * POST /api-tokens - Criar nova API
     */
    public static function create(): void
    {
        Auth::requireSuperAdmin();
        
        $name = trim(Request::input('name', ''));
        $tokenValue = trim(Request::input('token_value', ''));
        
        if (!$name) {
            Response::error('Nome da API é obrigatório', 400);
        }
        
        if (!$tokenValue) {
            Response::error('Token/Bearer é obrigatório', 400);
        }
        
        $pdo = getDBConnection();
        
        // Verificar se já existe API com mesmo nome
        $stmt = $pdo->prepare("SELECT id FROM api_tokens WHERE name = ?");
        $stmt->execute([$name]);
        if ($stmt->fetch()) {
            Response::error('Já existe uma API com este nome', 400);
        }
        
        $stmt = $pdo->prepare("
            INSERT INTO api_tokens (name, description, api_type, token_value, base_url, extra_headers, extra_config, test_endpoint)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        ");
        
        $extraHeaders = Request::input('extra_headers', null);
        $extraConfig = Request::input('extra_config', null);
        
        $stmt->execute([
            $name,
            Request::input('description', ''),
            Request::input('api_type', 'gov'),
            $tokenValue,
            Request::input('base_url', ''),
            $extraHeaders ? json_encode($extraHeaders) : null,
            $extraConfig ? json_encode($extraConfig) : null,
            Request::input('test_endpoint', '')
        ]);
        
        $apiId = $pdo->lastInsertId();
        
        logAudit('api_token_created', null, "API: {$name}", Request::ip());
        
        Response::success([
            'id' => $apiId,
            'name' => $name
        ], 'API criada com sucesso');
    }
    
    /**
     * PUT /api-token?id={id} - Atualizar API
     */
    public static function update(): void
    {
        Auth::requireSuperAdmin();
        
        $id = (int)Request::get('id', 0);
        
        if (!$id) {
            Response::error('ID da API é obrigatório', 400);
        }
        
        $pdo = getDBConnection();
        
        // Verificar se existe
        $stmt = $pdo->prepare("SELECT * FROM api_tokens WHERE id = ?");
        $stmt->execute([$id]);
        $existing = $stmt->fetch();
        
        if (!$existing) {
            Response::notFound('API não encontrada');
        }
        
        $name = trim(Request::input('name', $existing['name']));
        
        // Verificar nome duplicado (excluindo a própria)
        $stmt = $pdo->prepare("SELECT id FROM api_tokens WHERE name = ? AND id != ?");
        $stmt->execute([$name, $id]);
        if ($stmt->fetch()) {
            Response::error('Já existe outra API com este nome', 400);
        }
        
        // Se token_value não foi enviado, mantém o existente
        $tokenValue = Request::input('token_value', null);
        if ($tokenValue === null || $tokenValue === '') {
            $tokenValue = $existing['token_value'];
        }
        
        $extraHeaders = Request::input('extra_headers', null);
        $extraConfig = Request::input('extra_config', null);
        
        $stmt = $pdo->prepare("
            UPDATE api_tokens SET
                name = ?,
                description = ?,
                api_type = ?,
                token_value = ?,
                base_url = ?,
                extra_headers = ?,
                extra_config = ?,
                test_endpoint = ?,
                is_active = ?,
                updated_at = NOW()
            WHERE id = ?
        ");
        
        $stmt->execute([
            $name,
            Request::input('description', $existing['description']),
            Request::input('api_type', $existing['api_type']),
            $tokenValue,
            Request::input('base_url', $existing['base_url']),
            $extraHeaders ? json_encode($extraHeaders) : $existing['extra_headers'],
            $extraConfig ? json_encode($extraConfig) : $existing['extra_config'],
            Request::input('test_endpoint', $existing['test_endpoint']),
            Request::input('is_active', $existing['is_active']),
            $id
        ]);
        
        logAudit('api_token_updated', null, "API: {$name}", Request::ip());
        
        Response::success(null, 'API atualizada com sucesso');
    }
    
    /**
     * DELETE /api-token?id={id} - Excluir API
     */
    public static function delete(): void
    {
        Auth::requireSuperAdmin();
        
        $id = (int)Request::get('id', 0);
        
        if (!$id) {
            Response::error('ID da API é obrigatório', 400);
        }
        
        $pdo = getDBConnection();
        
        // Verificar se existe e quantos sites usam
        $stmt = $pdo->prepare("
            SELECT at.name, COUNT(s.id) as sites_using
            FROM api_tokens at
            LEFT JOIN sites s ON s.api_token_id = at.id
            WHERE at.id = ?
            GROUP BY at.id
        ");
        $stmt->execute([$id]);
        $api = $stmt->fetch();
        
        if (!$api) {
            Response::notFound('API não encontrada');
        }
        
        // Avisar se há sites usando
        if ($api['sites_using'] > 0) {
            // Apenas desvincular os sites
            $stmt = $pdo->prepare("UPDATE sites SET api_token_id = NULL WHERE api_token_id = ?");
            $stmt->execute([$id]);
        }
        
        // Deletar API
        $stmt = $pdo->prepare("DELETE FROM api_tokens WHERE id = ?");
        $stmt->execute([$id]);
        
        logAudit('api_token_deleted', null, "API: {$api['name']}", Request::ip());
        
        Response::success([
            'sites_unlinked' => $api['sites_using']
        ], 'API excluída com sucesso');
    }
    
    /**
     * POST /api-token-test?id={id} - Testar conexão da API
     */
    public static function test(): void
    {
        Auth::requireSuperAdmin();
        
        $id = (int)Request::get('id', 0);
        
        if (!$id) {
            Response::error('ID da API é obrigatório', 400);
        }
        
        $pdo = getDBConnection();
        $stmt = $pdo->prepare("SELECT * FROM api_tokens WHERE id = ?");
        $stmt->execute([$id]);
        $api = $stmt->fetch();
        
        if (!$api) {
            Response::notFound('API não encontrada');
        }
        
        // Se não tem URL base ou endpoint de teste
        if (empty($api['base_url']) && empty($api['test_endpoint'])) {
            Response::error('Esta API não possui URL base ou endpoint de teste configurados', 400);
        }
        
        $testUrl = $api['test_endpoint'] ?: $api['base_url'];
        
        // Fazer requisição de teste
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $testUrl,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 10,
            CURLOPT_CONNECTTIMEOUT => 5,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $api['token_value'],
                'Accept: application/json',
                'User-Agent: AdminPanel/1.0'
            ],
            CURLOPT_SSL_VERIFYPEER => false
        ]);
        
        // Headers extras se existirem
        if (!empty($api['extra_headers'])) {
            $extraHeaders = json_decode($api['extra_headers'], true);
            if (is_array($extraHeaders)) {
                $headers = [];
                foreach ($extraHeaders as $key => $value) {
                    $headers[] = "{$key}: {$value}";
                }
                curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge([
                    'Authorization: Bearer ' . $api['token_value'],
                    'Accept: application/json'
                ], $headers));
            }
        }
        
        $startTime = microtime(true);
        $response = curl_exec($ch);
        $responseTime = round((microtime(true) - $startTime) * 1000);
        
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        // Atualizar status do teste
        $testStatus = ($httpCode >= 200 && $httpCode < 400) ? 'success' : 'failed';
        
        $stmt = $pdo->prepare("
            UPDATE api_tokens SET 
                last_tested_at = NOW(), 
                last_test_status = ?
            WHERE id = ?
        ");
        $stmt->execute([$testStatus, $id]);
        
        Response::success([
            'url_tested' => $testUrl,
            'http_code' => $httpCode,
            'response_time_ms' => $responseTime,
            'status' => $testStatus,
            'error' => $error ?: null,
            'response_preview' => $response ? substr($response, 0, 500) : null
        ], $testStatus === 'success' ? 'API respondeu com sucesso' : 'Falha no teste');
    }
    
    /**
     * GET /api-tokens-select - Lista simplificada para selectbox
     */
    public static function listForSelect(): void
    {
        Auth::require(); // Qualquer usuário logado
        
        $pdo = getDBConnection();
        $stmt = $pdo->query("
            SELECT id, name, api_type, is_active
            FROM api_tokens
            WHERE is_active = 1
            ORDER BY name ASC
        ");
        
        Response::success($stmt->fetchAll());
    }
    
    /**
     * Obtém o token de uma API pelo ID (uso interno)
     * @return string|null
     */
    public static function getTokenById(int $apiId)
    {
        $pdo = getDBConnection();
        $stmt = $pdo->prepare("SELECT token_value FROM api_tokens WHERE id = ? AND is_active = 1");
        $stmt->execute([$apiId]);
        $result = $stmt->fetch();
        
        return $result ? $result['token_value'] : null;
    }
    
    /**
     * Obtém token de API de um site específico
     * @return array|null
     */
    public static function getTokenBySiteId(int $siteId)
    {
        $pdo = getDBConnection();
        $stmt = $pdo->prepare("
            SELECT at.id, at.name, at.token_value, at.base_url, at.extra_headers, at.extra_config
            FROM sites s
            INNER JOIN api_tokens at ON at.id = s.api_token_id AND at.is_active = 1
            WHERE s.id = ? AND s.is_active = 1
        ");
        $stmt->execute([$siteId]);
        
        return $stmt->fetch() ?: null;
    }
}
