<?php

/**
 * Testes para o Sistema de Notificações Fiscais
 * 
 * Testa endpoints de notificações, configurações e integração com rejeições.
 */

require_once __DIR__ . '/../bootstrap.php';

use Gestoreasy\Core\Http\Request;
use Gestoreasy\Core\Kernel;
use Gestoreasy\Core\Auth\Jwt;
use Gestoreasy\Core\Tenant\ConnectionManager;

function assertTrue($cond, $msg) { if (!$cond) { echo "FAIL: $msg\n"; exit(1); } }
function assertEquals($expected, $actual, $msg) { if ($expected !== $actual) { echo "FAIL: $msg (expected: $expected, got: $actual)\n"; exit(1); } }
function assertFalse($cond, $msg) { if ($cond) { echo "FAIL: $msg\n"; exit(1); } }
function assertStatus($response, $expectedStatus, $msg) { 
    if ($response->status !== $expectedStatus) { 
        echo "FAIL: $msg (expected status: $expectedStatus, got: {$response->status})\n"; 
        if (isset($response->body['error'])) echo "Error: " . $response->body['error'] . "\n";
        exit(1); 
    } 
}

// Configuração inicial
$kernel = new Kernel();

// Token admin para tenant default
$payload = [ 'sub' => 1, 'email' => 'admin@local', 'name' => 'Admin', 'tenant' => 'default', 'roles' => ['admin'] ];
$token = Jwt::sign($payload);
$authHeaders = [ 'x-tenant-id' => 'default', 'authorization' => 'Bearer ' . $token ];

// Garantir tabelas de notificações
$pdo = ConnectionManager::forTenant();

// Criar tabela fiscal_notifications
$pdo->exec('CREATE TABLE IF NOT EXISTS fiscal_notifications (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    type VARCHAR(50) NOT NULL,
    title VARCHAR(255) NOT NULL,
    message TEXT NOT NULL,
    severity ENUM("info", "warning", "error", "critical") DEFAULT "info",
    status ENUM("unread", "read", "dismissed") DEFAULT "unread",
    context_data JSON,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    read_at TIMESTAMP NULL,
    expires_at TIMESTAMP NULL,
    INDEX idx_user_status (user_id, status),
    INDEX idx_type_severity (type, severity),
    INDEX idx_created_at (created_at),
    INDEX idx_expires_at (expires_at)
)');

// Limpeza para garantir estado inicial previsível
try {
    $pdo->exec('DELETE FROM fiscal_notifications');
} catch (\Throwable $e) { /* tolera ausência/erro */ }

// Recriar tabela fiscal_notification_settings com o esquema esperado
try { $pdo->exec('DROP TABLE IF EXISTS fiscal_notification_settings'); } catch (\Throwable $e) { /* ignora */ }
$pdo->exec('CREATE TABLE IF NOT EXISTS fiscal_notification_settings (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL UNIQUE,
    -- Flags por tipo de notificação
    nfce_rejection_enabled BOOLEAN DEFAULT TRUE,
    nfe_rejection_enabled BOOLEAN DEFAULT TRUE,
    cte_rejection_enabled BOOLEAN DEFAULT TRUE,
    sped_deadline_enabled BOOLEAN DEFAULT TRUE,
    cert_expiry_enabled BOOLEAN DEFAULT TRUE,
    general_alert_enabled BOOLEAN DEFAULT TRUE,
    -- Severidade mínima
    min_severity ENUM("low", "medium", "high", "critical") DEFAULT "medium",
    -- Canais
    email_enabled BOOLEAN DEFAULT FALSE,
    browser_enabled BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)');

// Limpar/normalizar configurações para o usuário de teste
try {
    $stmt = $pdo->prepare('DELETE FROM fiscal_notification_settings WHERE user_id = ?');
    $stmt->execute([1]);
} catch (\Throwable $e) { /* tolera ausência/erro */ }

// Criar tabela nfce_emissions se não existir
$pdo->exec('CREATE TABLE IF NOT EXISTS nfce_emissions (
    id INT AUTO_INCREMENT PRIMARY KEY,
    chave VARCHAR(44) NOT NULL UNIQUE,
    numero INT NOT NULL,
    serie INT NOT NULL,
    status ENUM("pending", "authorized", "rejected", "cancelled") DEFAULT "pending",
    protocolo VARCHAR(20),
    xml_content TEXT,
    rejection_code VARCHAR(10),
    rejection_message TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)');

echo "=== Testes do Sistema de Notificações Fiscais ===\n\n";

// Primeiro, vamos testar se o módulo fiscal está carregado
echo "0. Testando se o módulo fiscal está carregado...\n";
$testRequest = new Request($authHeaders, [], [], [], 'GET', '/api/fiscal/nfce/emissions');
$testResponse = $kernel->handle($testRequest);
echo "Status do endpoint fiscal: " . $testResponse->status . "\n";
if ($testResponse->status !== 200) {
    echo "Erro no módulo fiscal: " . ($testResponse->body['error'] ?? 'Erro desconhecido') . "\n";
    exit(1);
}
echo "✓ Módulo fiscal carregado\n\n";

// 1. Testar listagem de notificações (inicialmente vazia)
echo "1. Testando listagem inicial de notificações...\n";
$reqNotifications = new Request($authHeaders, [], [], [], 'GET', '/api/fiscal/notifications');
$resNotifications = $kernel->handle($reqNotifications);
echo "Status: " . $resNotifications->status . "\n";
if ($resNotifications->status !== 200) {
    echo "Erro: " . ($resNotifications->body['error'] ?? 'Erro desconhecido') . "\n";
    echo "Body completo: " . json_encode($resNotifications->body) . "\n";
    exit(1);
}
assertStatus($resNotifications, 200, 'Listar notificações');
$notifications = $resNotifications->body;
assertTrue(is_array($notifications['notifications'] ?? null), 'Lista de notificações deve ser array');
assertEquals(0, $notifications['unread_count'] ?? -1, 'Contador inicial deve ser 0');
echo "✓ Listagem inicial OK (vazia)\n\n";

// 2. Testar configurações de notificação do usuário
echo "2. Testando configurações de notificação...\n";
$reqSettings = new Request($authHeaders, [], [], [], 'GET', '/api/fiscal/notifications/settings');
$resSettings = $kernel->handle($reqSettings);
assertStatus($resSettings, 200, 'Obter configurações de notificação');
$settings = $resSettings->body;
assertTrue(isset($settings['user_id']), 'Configurações devem ter user_id');
assertTrue($settings['nfce_rejection_enabled'] ?? false, 'NFC-e rejection deve estar habilitado por padrão');
echo "✓ Configurações padrão OK\n\n";

// 3. Atualizar configurações
echo "3. Testando atualização de configurações...\n";
$newSettings = [
    'min_severity' => 'high',
    'email_enabled' => true,
    'sped_deadline_enabled' => false
];
$reqUpdateSettings = new Request($authHeaders, [], $newSettings, [], 'PUT', '/api/fiscal/notifications/settings');
$resUpdateSettings = $kernel->handle($reqUpdateSettings);
assertStatus($resUpdateSettings, 200, 'Atualizar configurações');
echo "✓ Configurações atualizadas\n\n";

// 4. Verificar configurações atualizadas
echo "4. Verificando configurações atualizadas...\n";
$reqSettingsUpdated = new Request($authHeaders, [], [], [], 'GET', '/api/fiscal/notifications/settings');
$resSettingsUpdated = $kernel->handle($reqSettingsUpdated);
assertStatus($resSettingsUpdated, 200, 'Obter configurações atualizadas');
$updatedSettings = $resSettingsUpdated->body;
assertEquals('high', $updatedSettings['min_severity'] ?? '', 'Severidade mínima deve ser high');
assertTrue($updatedSettings['email_enabled'] ?? false, 'Email deve estar habilitado');
assertFalse($updatedSettings['sped_deadline_enabled'] ?? true, 'SPED deadline deve estar desabilitado');
echo "✓ Configurações verificadas\n\n";

// 5. Simular emissão de NFC-e para gerar possível notificação de rejeição
echo "5. Testando emissão de NFC-e (pode gerar notificação de rejeição)...\n";
$nfceBody = [
    'sale_id' => '999',
    'descricao' => 'Produto de teste para notificação',
    'valor' => 50.00,
    'environment' => 'homolog'
];

// Tentar várias vezes para aumentar chance de rejeição (5% por tentativa)
$rejectionFound = false;
$attempts = 0;
$maxAttempts = 20; // Máximo 20 tentativas

while (!$rejectionFound && $attempts < $maxAttempts) {
    $attempts++;
    $reqNfce = new Request($authHeaders, [], $nfceBody, [], 'POST', '/api/fiscal/nfce/autorizar');
    $resNfce = $kernel->handle($reqNfce);
    
    if ($resNfce->statusCode === 200) {
        $nfceResult = $resNfce->body;
        if (($nfceResult['status'] ?? '') === 'rejected') {
            $rejectionFound = true;
            echo "✓ Rejeição simulada encontrada na tentativa {$attempts}: {$nfceResult['rejection_message']}\n";
            
            // Aguardar um pouco para garantir que a notificação foi criada
            usleep(100000); // 100ms
            
            // Verificar se notificação foi criada
            $reqNotificationsAfter = new Request($authHeaders, [], [], [], 'GET', '/api/fiscal/notifications');
            $resNotificationsAfter = $kernel->handle($reqNotificationsAfter);
            assertStatus($resNotificationsAfter, 200, 'Listar notificações após rejeição');
            $notificationsAfter = $resNotificationsAfter->body;
            
            if (($notificationsAfter['unread_count'] ?? 0) > 0) {
                echo "✓ Notificação de rejeição criada automaticamente\n";
                
                // Testar marcar como lida
                $firstNotification = $notificationsAfter['notifications'][0] ?? null;
                if ($firstNotification && isset($firstNotification['id'])) {
                    $notificationId = $firstNotification['id'];
                    
                    echo "6. Testando marcar notificação como lida...\n";
                    $reqMarkRead = new Request($authHeaders, [], [], [], 'POST', "/api/fiscal/notifications/{$notificationId}/read");
                    $resMarkRead = $kernel->handle($reqMarkRead);
                    assertStatus($resMarkRead, 200, 'Marcar notificação como lida');
                    echo "✓ Notificação marcada como lida\n\n";
                    
                    // Verificar contador atualizado
                    $reqNotificationsFinal = new Request($authHeaders, [], [], [], 'GET', '/api/fiscal/notifications');
                    $resNotificationsFinal = $kernel->handle($reqNotificationsFinal);
                    $notificationsFinal = $resNotificationsFinal->body;
                    assertEquals(0, $notificationsFinal['unread_count'] ?? -1, 'Contador deve ser 0 após marcar como lida');
                    echo "✓ Contador de não lidas atualizado\n\n";
                }
            } else {
                echo "⚠ Rejeição encontrada mas notificação não foi criada (possível erro)\n";
            }
            break;
        }
    }
    
    // Pequena pausa entre tentativas
    usleep(50000); // 50ms
}

if (!$rejectionFound) {
    echo "⚠ Nenhuma rejeição encontrada em {$maxAttempts} tentativas (probabilidade baixa)\n";
    echo "  Testando criação manual de notificação...\n";
    
    // Criar notificação manualmente para testar funcionalidades
    try {
        $notificationService = new \Core\Fiscal\FiscalNotificationService();
        $notificationId = $notificationService->createRejectionNotification(
            'nfce',
            '33240999999999000191650010000000011234567890',
            '204',
            'Duplicidade de NF-e (teste manual)',
            1 // user_id
        );
        echo "✓ Notificação criada manualmente (ID: {$notificationId})\n";
        
        // Testar dispensar notificação
        echo "7. Testando dispensar notificação...\n";
        $reqDismiss = new Request($authHeaders, [], [], [], 'POST', "/api/fiscal/notifications/{$notificationId}/dismiss");
        $resDismiss = $kernel->handle($reqDismiss);
        assertStatus($resDismiss, 200, 'Dispensar notificação');
        echo "✓ Notificação dispensada\n\n";
        
    } catch (\Throwable $e) {
        echo "✗ Erro ao criar notificação manual: " . $e->getMessage() . "\n";
    }
}

// 8. Testar verificação de prazos
echo "8. Testando verificação de prazos...\n";
$reqCheckDeadlines = new Request($authHeaders, [], [], [], 'POST', '/api/fiscal/notifications/check-deadlines');
$resCheckDeadlines = $kernel->handle($reqCheckDeadlines);
assertStatus($resCheckDeadlines, 200, 'Verificar prazos');
$deadlineResult = $resCheckDeadlines->body;
assertTrue(isset($deadlineResult['alerts_created']), 'Resultado deve conter alerts_created');
assertTrue(isset($deadlineResult['expired_cleaned']), 'Resultado deve conter expired_cleaned');
echo "✓ Verificação de prazos executada\n";
echo "  - Alertas criados: " . ($deadlineResult['alerts_created'] ?? 0) . "\n";
echo "  - Notificações expiradas limpas: " . ($deadlineResult['expired_cleaned'] ?? 0) . "\n\n";

// 9. Testar filtros de notificação
echo "9. Testando filtros de notificação...\n";
$reqFilterUnread = new Request($authHeaders, ['status' => 'unread'], [], [], 'GET', '/api/fiscal/notifications');
$resFilterUnread = $kernel->handle($reqFilterUnread);
assertStatus($resFilterUnread, 200, 'Filtrar notificações não lidas');

$reqFilterRead = new Request($authHeaders, ['status' => 'read'], [], [], 'GET', '/api/fiscal/notifications');
$resFilterRead = $kernel->handle($reqFilterRead);
assertStatus($resFilterRead, 200, 'Filtrar notificações lidas');

$reqFilterDismissed = new Request($authHeaders, ['status' => 'dismissed'], [], [], 'GET', '/api/fiscal/notifications');
$resFilterDismissed = $kernel->handle($reqFilterDismissed);
assertStatus($resFilterDismissed, 200, 'Filtrar notificações dispensadas');
echo "✓ Filtros de notificação funcionando\n\n";

echo "=== Todos os testes de notificações fiscais concluídos com sucesso! ===\n";
echo "Funcionalidades testadas:\n";
echo "- ✓ Listagem de notificações com filtros\n";
echo "- ✓ Configurações de usuário (obter/atualizar)\n";
echo "- ✓ Integração com rejeições de NFC-e\n";
echo "- ✓ Marcar como lida/dispensar\n";
echo "- ✓ Verificação automática de prazos\n";
echo "- ✓ Limpeza de notificações expiradas\n";
echo "- ✓ Contadores de não lidas\n\n";