#!/usr/bin/env php
<?php

/**
 * Script d'initialisation des tables de sécurité
 * Crée les tables si elles n'existent pas
 */

declare(strict_types=1);

require_once __DIR__ . '/../../bootstrap.php';
require_once __DIR__ . '/../../src/Config/AppConfig.php';
require_once __DIR__ . '/../../src/Core/Database.php';

// Initialiser la configuration
$appConfig = AppConfig::getInstance();
$config = $appConfig->getFullConfig();

// Initialiser la base de données
Database::init($config['database']);
$db = Database::getInstance();

echo "\n========================================\n";
echo "  CRÉATION DES TABLES DE SÉCURITÉ\n";
echo "========================================\n\n";

try {
    // Désactiver temporairement le mode strict pour les clés étrangères
    $db->exec("SET FOREIGN_KEY_CHECKS = 0");
    
    // 1. Table des alertes
    echo "1. Création de la table sec_alerts...\n";
    $db->exec("
        CREATE TABLE IF NOT EXISTS `sec_alerts` (
            `id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
            `alert_type` VARCHAR(50) NOT NULL COMMENT 'Type d\'alerte (BRUTE_FORCE, SQL_ERROR, etc.)',
            `alert_level` ENUM('INFO', 'WARNING', 'ERROR', 'CRITICAL', 'SECURITY') NOT NULL DEFAULT 'INFO',
            `ip_address` VARCHAR(45) DEFAULT NULL COMMENT 'Adresse IP source',
            `user_id` INT(11) UNSIGNED DEFAULT NULL COMMENT 'ID utilisateur si connecté',
            `username` VARCHAR(255) DEFAULT NULL COMMENT 'Username tenté ou utilisé',
            `endpoint` VARCHAR(255) DEFAULT NULL COMMENT 'Endpoint API concerné',
            `method` VARCHAR(10) DEFAULT NULL COMMENT 'Méthode HTTP',
            `details` JSON DEFAULT NULL COMMENT 'Détails additionnels en JSON',
            `occurrences` INT(11) DEFAULT 1 COMMENT 'Nombre d\'occurrences',
            `first_seen` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
            `last_seen` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            `email_sent` TINYINT(1) DEFAULT 0 COMMENT 'Email d\'alerte envoyé',
            `email_sent_at` TIMESTAMP NULL DEFAULT NULL,
            `resolved` TINYINT(1) DEFAULT 0 COMMENT 'Alerte résolue',
            `resolved_at` TIMESTAMP NULL DEFAULT NULL,
            `resolved_by` INT(11) UNSIGNED DEFAULT NULL COMMENT 'ID admin qui a résolu',
            `notes` TEXT DEFAULT NULL COMMENT 'Notes de résolution',
            KEY `idx_ip` (`ip_address`),
            KEY `idx_type_time` (`alert_type`, `last_seen`),
            KEY `idx_level` (`alert_level`),
            KEY `idx_resolved` (`resolved`),
            KEY `idx_user` (`user_id`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Alertes de sécurité et monitoring'
    ");
    echo "   ✓ Table sec_alerts créée\n";
    
    // 2. Table des métriques de performance (SANS PARTITIONNEMENT)
    echo "2. Création de la table sec_performance_metrics...\n";
    $db->exec("
        CREATE TABLE IF NOT EXISTS `sec_performance_metrics` (
            `id` BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
            `endpoint` VARCHAR(255) NOT NULL COMMENT 'Endpoint API',
            `method` VARCHAR(10) NOT NULL COMMENT 'Méthode HTTP',
            `response_time_ms` INT(11) NOT NULL COMMENT 'Temps de réponse total en ms',
            `db_time_ms` INT(11) DEFAULT 0 COMMENT 'Temps cumulé des requêtes DB en ms',
            `db_queries_count` INT(11) DEFAULT 0 COMMENT 'Nombre de requêtes DB',
            `memory_peak_mb` FLOAT DEFAULT NULL COMMENT 'Pic mémoire en MB',
            `memory_start_mb` FLOAT DEFAULT NULL COMMENT 'Mémoire au début en MB',
            `http_status` INT(11) DEFAULT NULL COMMENT 'Code HTTP de réponse',
            `user_id` INT(11) UNSIGNED DEFAULT NULL COMMENT 'ID utilisateur si connecté',
            `ip_address` VARCHAR(45) DEFAULT NULL COMMENT 'Adresse IP',
            `user_agent` TEXT DEFAULT NULL COMMENT 'User Agent complet',
            `request_size` INT(11) DEFAULT NULL COMMENT 'Taille de la requête en octets',
            `response_size` INT(11) DEFAULT NULL COMMENT 'Taille de la réponse en octets',
            `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
            KEY `idx_endpoint_time` (`endpoint`, `created_at`),
            KEY `idx_response_time` (`response_time_ms`),
            KEY `idx_created` (`created_at`),
            KEY `idx_status` (`http_status`),
            KEY `idx_user` (`user_id`),
            KEY `idx_date_endpoint` (`created_at`, `endpoint`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Métriques de performance des requêtes'
    ");
    echo "   ✓ Table sec_performance_metrics créée\n";
    
    // 3. Table des tentatives de login échouées
    echo "3. Création de la table sec_failed_login_attempts...\n";
    $db->exec("
        CREATE TABLE IF NOT EXISTS `sec_failed_login_attempts` (
            `id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
            `username` VARCHAR(255) DEFAULT NULL COMMENT 'Username tenté',
            `encrypted_username` VARCHAR(255) DEFAULT NULL COMMENT 'Username chiffré si trouvé',
            `ip_address` VARCHAR(45) NOT NULL COMMENT 'Adresse IP',
            `user_agent` TEXT DEFAULT NULL COMMENT 'User Agent',
            `attempt_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
            `error_type` VARCHAR(50) DEFAULT NULL COMMENT 'Type d\'erreur (invalid_password, user_not_found, etc.)',
            `country_code` VARCHAR(2) DEFAULT NULL COMMENT 'Code pays de l\'IP (si géoloc activée)',
            KEY `idx_ip_time` (`ip_address`, `attempt_time`),
            KEY `idx_username` (`username`),
            KEY `idx_encrypted_username` (`encrypted_username`),
            KEY `idx_time` (`attempt_time`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Tentatives de connexion échouées'
    ");
    echo "   ✓ Table sec_failed_login_attempts créée\n";
    
    // 4. Table des IPs bloquées
    echo "4. Création de la table sec_blocked_ips...\n";
    $db->exec("
        CREATE TABLE IF NOT EXISTS `sec_blocked_ips` (
            `ip_address` VARCHAR(45) NOT NULL PRIMARY KEY COMMENT 'Adresse IP bloquée',
            `reason` VARCHAR(255) NOT NULL COMMENT 'Raison du blocage',
            `details` JSON DEFAULT NULL COMMENT 'Détails additionnels',
            `blocked_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
            `blocked_until` TIMESTAMP NOT NULL COMMENT 'Bloqué jusqu\'à',
            `blocked_by` VARCHAR(50) DEFAULT 'system' COMMENT 'Qui a bloqué (system ou user ID)',
            `permanent` TINYINT(1) DEFAULT 0 COMMENT 'Blocage permanent',
            `unblocked_at` TIMESTAMP NULL DEFAULT NULL COMMENT 'Date de déblocage effectif',
            `unblocked_by` INT(11) UNSIGNED DEFAULT NULL COMMENT 'Qui a débloqué',
            `block_count` INT(11) DEFAULT 1 COMMENT 'Nombre de fois bloquée',
            KEY `idx_blocked_until` (`blocked_until`),
            KEY `idx_permanent` (`permanent`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='IPs bloquées temporairement ou définitivement'
    ");
    echo "   ✓ Table sec_blocked_ips créée\n";
    
    // 5. Créer les vues
    echo "5. Création des vues...\n";
    
    // Vue pour les alertes actives
    $db->exec("
        CREATE OR REPLACE VIEW sec_active_alerts AS
        SELECT 
            a.*,
            u.encrypted_name as user_name,
            r.encrypted_name as resolver_name
        FROM sec_alerts a
        LEFT JOIN users u ON a.user_id = u.id
        LEFT JOIN users r ON a.resolved_by = r.id
        WHERE a.resolved = 0
           OR (a.resolved = 1 AND a.resolved_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR))
        ORDER BY 
            CASE a.alert_level 
                WHEN 'SECURITY' THEN 1
                WHEN 'CRITICAL' THEN 2
                WHEN 'ERROR' THEN 3
                WHEN 'WARNING' THEN 4
                WHEN 'INFO' THEN 5
            END,
            a.last_seen DESC
    ");
    echo "   ✓ Vue sec_active_alerts créée\n";
    
    // Vue pour les IPs suspectes
    $db->exec("
        CREATE OR REPLACE VIEW sec_suspicious_ips AS
        SELECT 
            ip_address,
            COUNT(*) as total_attempts,
            COUNT(DISTINCT username) as unique_usernames,
            MIN(attempt_time) as first_attempt,
            MAX(attempt_time) as last_attempt,
            TIMESTAMPDIFF(MINUTE, MIN(attempt_time), MAX(attempt_time)) as timespan_minutes
        FROM sec_failed_login_attempts
        WHERE attempt_time >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
        GROUP BY ip_address
        HAVING total_attempts >= 5
            OR unique_usernames >= 3
        ORDER BY total_attempts DESC
    ");
    echo "   ✓ Vue sec_suspicious_ips créée\n";
    
    // 6. Créer les index additionnels
    echo "6. Création des index additionnels...\n";
    
    // Index pour les requêtes fréquentes
    $db->exec("CREATE INDEX IF NOT EXISTS idx_sec_metrics_recent ON sec_performance_metrics(created_at DESC, endpoint)");
    $db->exec("CREATE INDEX IF NOT EXISTS idx_sec_alerts_recent ON sec_alerts(last_seen DESC, alert_level)");
    $db->exec("CREATE INDEX IF NOT EXISTS idx_sec_failed_recent ON sec_failed_login_attempts(attempt_time DESC, ip_address)");
    echo "   ✓ Index créés\n";
    
    // 7. Créer la procédure de nettoyage
    echo "7. Création de la procédure de nettoyage...\n";
    $db->exec("DROP PROCEDURE IF EXISTS sec_cleanup_old_data");
    $db->exec("
        CREATE PROCEDURE sec_cleanup_old_data(IN days_to_keep INT)
        BEGIN
            -- Nettoyer les métriques de performance
            DELETE FROM sec_performance_metrics 
            WHERE created_at < DATE_SUB(NOW(), INTERVAL days_to_keep DAY);
            
            -- Nettoyer les tentatives de login
            DELETE FROM sec_failed_login_attempts 
            WHERE attempt_time < DATE_SUB(NOW(), INTERVAL days_to_keep DAY);
            
            -- Nettoyer les alertes résolues
            DELETE FROM sec_alerts 
            WHERE resolved = 1 
              AND resolved_at < DATE_SUB(NOW(), INTERVAL days_to_keep DAY);
            
            -- Retourner le nombre de lignes supprimées
            SELECT ROW_COUNT() as deleted_rows;
        END
    ");
    echo "   ✓ Procédure sec_cleanup_old_data créée\n";
    
    // Réactiver les clés étrangères
    $db->exec("SET FOREIGN_KEY_CHECKS = 1");
    
    // 8. Vérifier que tout est créé
    echo "\n8. Vérification finale...\n";
    $tables = ['sec_alerts', 'sec_performance_metrics', 'sec_failed_login_attempts', 'sec_blocked_ips'];
    $allOk = true;
    
    foreach ($tables as $table) {
        $stmt = $db->query("SELECT COUNT(*) as count FROM $table");
        if ($stmt) {
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            echo "   ✓ Table $table : OK ({$result['count']} enregistrements)\n";
        } else {
            echo "   ✗ Table $table : ERREUR\n";
            $allOk = false;
        }
    }
    
    if ($allOk) {
        echo "\n========================================\n";
        echo "✅ TOUTES LES TABLES ONT ÉTÉ CRÉÉES AVEC SUCCÈS\n";
        echo "========================================\n\n";
        echo "Le système de sécurité est maintenant prêt à être utilisé.\n";
        echo "Vous pouvez tester avec : php test_security.php\n\n";
    } else {
        echo "\n⚠️ Certaines tables n'ont pas pu être créées.\n";
        echo "Vérifiez les erreurs ci-dessus.\n\n";
    }
    
} catch (PDOException $e) {
    echo "\n❌ ERREUR SQL : " . $e->getMessage() . "\n\n";
    echo "Code d'erreur : " . $e->getCode() . "\n";
    echo "Vérifiez les permissions et la configuration de la base de données.\n\n";
    exit(1);
} catch (Exception $e) {
    echo "\n❌ ERREUR : " . $e->getMessage() . "\n\n";
    exit(1);
}