<?php
// src/controllers/AuthController.php
require_once __DIR__ . '/../helpers/SecurityHelper.php';

class AuthController {
    public static function login($db) {
        // Configurar sesión segura - MOVIDO AL INDEX.PHP
        
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            validate_csrf();
            
            $email = trim($_POST['email'] ?? '');
            $pass = $_POST['password'] ?? '';
            $ip_address = get_client_ip();
            
            // Validaciones básicas
            if (empty($email) || empty($pass)) {
                SecurityHelper::logSecurityEvent($db, 'login_failed', 'Campos vacíos');
                flash('error', 'Todos los campos son obligatorios.');
                redirect('login');
                return;
            }
            
            if (!validate_email($email)) {
                SecurityHelper::logSecurityEvent($db, 'login_failed', 'Email inválido: ' . $email);
                flash('error', 'El formato del email no es válido.');
                redirect('login');
                return;
            }
            
            // Verificar rate limiting por IP
            if ($lock_time = SecurityHelper::isRateLimited($db, $ip_address, false)) {
                SecurityHelper::logSecurityEvent($db, 'login_blocked_ip', 'IP bloqueada: ' . $ip_address);
                flash('error', 'Demasiados intentos. Intenta nuevamente en ' . format_lock_time($lock_time));
                redirect('login');
                return;
            }
            
            // Verificar rate limiting por email
            if ($lock_time = SecurityHelper::isRateLimited($db, $email, true)) {
                SecurityHelper::logSecurityEvent($db, 'login_blocked_user', 'Usuario bloqueado: ' . $email);
                flash('error', 'Demasiados intentos. Intenta nuevamente en ' . format_lock_time($lock_time));
                redirect('login');
                return;
            }
            
            // Buscar usuario
            $stmt = $db->prepare("SELECT id, username, email, password_hash, role, email_verified, failed_attempts, locked_until, avatar_url FROM users WHERE email = ? LIMIT 1");
            $stmt->execute([$email]);
            $user = $stmt->fetch();
            
            // Verificar si el usuario existe y está verificado
            if (!$user) {
                SecurityHelper::recordFailedAttempt($db, $ip_address, false);
                SecurityHelper::recordFailedAttempt($db, $email, true);
                SecurityHelper::logSecurityEvent($db, 'login_failed', 'Usuario no encontrado: ' . $email);
                
                // Mensaje genérico para evitar enumeración
                flash('error', 'Credenciales inválidas.');
                redirect('login');
                return;
            }
            
            // Verificar si el email está verificado
            if (!$user['email_verified']) {
                SecurityHelper::logSecurityEvent($db, 'login_failed', 'Email no verificado: ' . $email, $user['id']);
                flash('error', 'Debes verificar tu email antes de iniciar sesión.');
                redirect('login');
                return;
            }
            
            // Verificar si la cuenta está bloqueada
            if ($user['locked_until'] && strtotime($user['locked_until']) > time()) {
                SecurityHelper::logSecurityEvent($db, 'login_blocked_account', 'Cuenta bloqueada: ' . $email, $user['id']);
                flash('error', 'Cuenta bloqueada. Intenta nuevamente en ' . format_lock_time($user['locked_until']));
                redirect('login');
                return;
            }
            
            // Verificar contraseña
            if ($user && password_verify($pass, $user['password_hash'])) {
                // Login exitoso - limpiar intentos fallidos
                SecurityHelper::clearFailedAttempts($db, $ip_address, false);
                SecurityHelper::clearFailedAttempts($db, $email, true);
                
                // Reiniciar contador de intentos fallidos
                $db->prepare("UPDATE users SET failed_attempts = 0, locked_until = NULL, last_login = NOW() WHERE id = ?")->execute([$user['id']]);
                
                // Configurar sesión
                $_SESSION['user'] = [
                    'id' => $user['id'], 
                    'username' => $user['username'], 
                    'email' => $user['email'],
                    'role' => $user['role'] ?? 'user',
                    'email_verified' => $user['email_verified'],
                    'avatar_url' => $user['avatar_url'] ?? null
                ];
                
                // Registrar login exitoso
                SecurityHelper::logSecurityEvent($db, 'login_success', null, $user['id']);
                
                // Actualizar last_active
                $db->prepare("UPDATE users SET last_active = NOW() WHERE id = ?")->execute([$user['id']]);
                
                // Redirigir según rol
                if (($user['role'] ?? 'user') === 'admin') {
                    redirect('admin/dashboard');
                } else {
                    redirect('dashboard');
                }
            } else {
                // Login fallido
                SecurityHelper::recordFailedAttempt($db, $ip_address, false);
                SecurityHelper::recordFailedAttempt($db, $email, true);
                
                // Incrementar intentos fallidos del usuario
                $new_attempts = $user['failed_attempts'] + 1;
                $locked_until = null;
                
                // Bloquear cuenta si supera el máximo de intentos
                if ($new_attempts >= SecurityHelper::MAX_LOGIN_ATTEMPTS) {
                    $locked_until = date('Y-m-d H:i:s', time() + SecurityHelper::LOCKOUT_DURATION);
                }
                
                $db->prepare("UPDATE users SET failed_attempts = ?, locked_until = ? WHERE id = ?")
                   ->execute([$new_attempts, $locked_until, $user['id']]);
                
                SecurityHelper::logSecurityEvent($db, 'login_failed', 'Contraseña incorrecta', $user['id']);
                
                // Mensaje genérico
                flash('error', 'Credenciales inválidas.');
                redirect('login');
            }
        }
        
        view('auth/login');
    }

    public static function register($db) {
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            validate_csrf();
            
            $username = trim($_POST['username'] ?? '');
            $email = trim($_POST['email'] ?? '');
            $email_confirm = trim($_POST['email_confirm'] ?? '');
            $birth = $_POST['birth_date'] ?? '';
            $pass = $_POST['password'] ?? '';
            $pass_confirm = $_POST['password_confirm'] ?? '';
            $invite = trim($_POST['invite_code'] ?? '');

            // EXTRA LOCATION FIELDS
            $gender = trim($_POST['gender'] ?? '');
            $country = trim($_POST['country'] ?? '');
            $region  = trim($_POST['region'] ?? '');
            $city    = trim($_POST['city'] ?? '');
            

            // Validaciones
            $errors = [];
            // VALIDACION_UBICACION
            if ($gender==='') { $errors[]='Selecciona tu género.'; }
            if ($country==='') { $errors[]='Selecciona tu país.'; }
            if ($country==='ES') {
                if ($region==='')  { $errors[]='Selecciona tu comunidad.'; }
                if ($city==='')    { $errors[]='Selecciona tu ciudad.'; }
            }
            if ($gender==='') { $errors[]='Selecciona tu género.'; }
            if ($country==='') { $errors[]='Selecciona tu país.'; }
            if ($region==='')  { $errors[]='Selecciona tu región.'; }
            if ($city==='')    { $errors[]='Indica tu ciudad.'; }
            
            // Validación simple España
            
            
            if ($username === '' || $email === '' || $email_confirm === '' || 
                $pass === '' || $pass_confirm === '' || $invite === '' || $birth === '') {
                $errors[] = 'Todos los campos son obligatorios.';
            }
            
            if ($email !== $email_confirm) {
                $errors[] = 'Los emails no coinciden.';
            }
            
            if (!validate_email($email)) {
                $errors[] = 'El formato del email no es válido.';
            }
            
            if ($pass !== $pass_confirm) {
                $errors[] = 'Las contraseñas no coinciden.';
            }
            
            // Validar fuerza de contraseña
            $password_strength = validate_password_strength($pass);
            if ($password_strength !== true) {
                $errors[] = $password_strength;
            }
            
            // Validar edad (mayor de 16 años)
            if (!is_over_16($birth)) {
                $errors[] = 'Debes tener al menos 16 años para registrarte.';
            }
            
            if (!empty($errors)) {
                foreach ($errors as $error) {
                    flash('error', $error);
                }
                redirect('register');
                return;
            }
            
            // Verificar username/email únicos
            $exists = $db->prepare("SELECT 1 FROM users WHERE username = ? OR email = ? LIMIT 1");
            $exists->execute([$username, $email]);
            
            if ($exists->fetch()) {
                flash('error', 'Nombre de usuario or email ya registrados.');
                redirect('register');
                return;
            }
            
            // Invitación válida y sin usar
            $inv = $db->prepare("SELECT id, code, used_by FROM invites WHERE code = ? LIMIT 1");
            $inv->execute([$invite]);
            $row = $inv->fetch();
            
            if (!$row) {
                flash('error', 'Código de invitación inválido.');
                redirect('register');
                return;
            } elseif (!empty($row['used_by'])) {
                flash('error', 'Este código ya fue usado.');
                redirect('register');
                return;
            }
            
            $hash = password_hash($pass, PASSWORD_BCRYPT);
            
            // Crear usuario (UUID)
            // DYNAMIC OPTIONAL COLUMNS
            $baseCols = ['username','email','birth_date','date_of_birth','password_hash'];
            $baseVals = [$username, $email, $birth, $birth, $hash];

            // Detect optional columns in users table
            try {
                $colsStmt = $db->query("SHOW COLUMNS FROM users");
                $cols = $colsStmt->fetchAll(PDO::FETCH_COLUMN, 0);
                $have = function($c) use ($cols) { return in_array($c, $cols, true); };

                if ($have('gender'))        { $baseCols[]='gender';        $baseVals[]=$gender ?? null; }
                if ($have('country_code'))  { $baseCols[]='country_code';  $baseVals[]=$country ?? null; }
                elseif ($have('country'))   { $baseCols[]='country';       $baseVals[]=$country ?? null; }
                if ($have('region'))        { $baseCols[]='region';        $baseVals[]=$region ?? null; }
                if ($have('city'))          { $baseCols[]='city';          $baseVals[]=$city ?? null; }
                if ($have('postal_code'))   { $baseCols[]='postal_code';   $baseVals[]=$postal ?? null; }
            } catch (Throwable $t) {}

            $colsSql = 'id, ' . implode(', ', $baseCols) . ', invites_left, created_at';
            $placeholders = 'UUID(),' . rtrim(str_repeat('?,', count($baseVals)), ',') . ',5,NOW()';
            $sql = "INSERT INTO users ($colsSql) VALUES ($placeholders)";
            $stmt = $db->prepare($sql);
            $stmt->execute($baseVals);
            
            // Obtener usuario por email
            $sel = $db->prepare("SELECT id, username, email FROM users WHERE email = ? LIMIT 1");
            $sel->execute([$email]);
            $newUser = $sel->fetch();
            
            // Marcar invitación usada
            $upd = $db->prepare("UPDATE invites SET used_by = ?, used_at = NOW() WHERE id = ?");
            $upd->execute([$newUser['id'], $row['id']]);
            
            // Crear token de verificación de email
            $token = SecurityHelper::generateToken();
            $expires = date('Y-m-d H:i:s', time() + (24 * 60 * 60)); // 24 horas
            
            $token_stmt = $db->prepare("
                INSERT INTO email_verifications (id, user_id, token, created_at, expires_at)
                VALUES (UUID(), ?, ?, NOW(), ?)
            ");
            $token_stmt->execute([$newUser['id'], $token, $expires]);
            
            // Enviar email de verificación (simulado)
            self::sendVerificationEmail($email, $token, $username);
            
            SecurityHelper::logSecurityEvent($db, 'register_success', 'Usuario registrado: ' . $email, $newUser['id']);
            
            flash('success', 'Cuenta creada correctamente. Por favor verifica tu email.');
            redirect('login');
        }
        
        view('auth/register');
    }

    public static function verifyEmail($db) {
        $token = $_GET['token'] ?? '';
        
        if (empty($token)) {
            flash('error', 'Token de verificación inválido.');
            redirect('login');
            return;
        }
        
        // Buscar token
        $stmt = $db->prepare("
            SELECT ev.*, u.id as user_id, u.username, u.email 
            FROM email_verifications ev 
            JOIN users u ON ev.user_id = u.id 
            WHERE ev.token = ? AND ev.expires_at > NOW()
        ");
        $stmt->execute([$token]);
        $verification = $stmt->fetch();
        
        if (!$verification) {
            flash('error', 'Token de verificación inválido o expirado.');
            redirect('login');
            return;
        }
        
        // Marcar email como verificado
        $update = $db->prepare("UPDATE users SET email_verified = 1, verified_at = NOW() WHERE id = ?");
        $update->execute([$verification['user_id']]);
        
        // Eliminar token
        $delete = $db->prepare("DELETE FROM email_verifications WHERE token = ?");
        $delete->execute([$token]);
        
        SecurityHelper::logSecurityEvent($db, 'email_verified', null, $verification['user_id']);
        
        flash('success', 'Email verificado correctamente. Ya puedes iniciar sesión.');
        redirect('login');
    }

    public static function resendVerification($db) {
        require_login();
        $user_id = $_SESSION['user']['id'];
        
        // Verificar si ya está verificado
        $stmt = $db->prepare("SELECT email_verified, email FROM users WHERE id = ?");
        $stmt->execute([$user_id]);
        $user = $stmt->fetch();
        
        if ($user['email_verified']) {
            flash('info', 'Tu email ya está verificado.');
            redirect('profile');
            return;
        }
        
        // Eliminar tokens anteriores
        $db->prepare("DELETE FROM email_verifications WHERE user_id = ?")->execute([$user_id]);
        
        // Crear nuevo token
        $token = SecurityHelper::generateToken();
        $expires = date('Y-m-d H:i:s', time() + (24 * 60 * 60)); // 24 horas
        
        $token_stmt = $db->prepare("
            INSERT INTO email_verifications (id, user_id, token, created_at, expires_at)
            VALUES (UUID(), ?, ?, NOW(), ?)
        ");
        $token_stmt->execute([$user_id, $token, $expires]);
        
        // Enviar email de verificación
        self::sendVerificationEmail($user['email'], $token, $_SESSION['user']['username']);
        
        SecurityHelper::logSecurityEvent($db, 'verification_resent', null, $user_id);
        
        flash('success', 'Email de verificación reenviado. Revisa tu bandeja de entrada.');
        redirect('profile');
    }

    public static function forgotPassword($db) {
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            validate_csrf();
            
            $email = trim($_POST['email'] ?? '');
            
            if (empty($email) || !validate_email($email)) {
                flash('error', 'Por favor ingresa un email válido.');
                redirect('auth/forgot-password');
                return;
            }
            
            // Buscar usuario
            $stmt = $db->prepare("SELECT id, username, email FROM users WHERE email = ?");
            $stmt->execute([$email]);
            $user = $stmt->fetch();
            
            if ($user) {
                // Eliminar tokens anteriores
                $db->prepare("DELETE FROM password_resets WHERE user_id = ?")->execute([$user['id']]);
                
                // Crear token de reset
                $token = SecurityHelper::generateToken();
                $expires = date('Y-m-d H:i:s', time() + (1 * 60 * 60)); // 1 hora
                
                $token_stmt = $db->prepare("
                    INSERT INTO password_resets (id, user_id, token, created_at, expires_at)
                    VALUES (UUID(), ?, ?, NOW(), ?)
                ");
                $token_stmt->execute([$user['id'], $token, $expires]);
                
                // Enviar email de reset
                self::sendPasswordResetEmail($user['email'], $token, $user['username']);
                
                SecurityHelper::logSecurityEvent($db, 'password_reset_requested', null, $user['id']);
            }
            
            // Mostrar mismo mensaje aunque el email no exista (por seguridad)
            flash('success', 'Si el email existe en nuestro sistema, recibirás instrucciones para resetear tu contraseña.');
            redirect('login');
        }
        
        view('auth/forgot-password');
    }

    public static function resetPassword($db) {
        $token = $_GET['token'] ?? '';
        
        if (empty($token)) {
            flash('error', 'Token de reset inválido.');
            redirect('login');
            return;
        }
        
        // Verificar token
        $stmt = $db->prepare("
            SELECT pr.*, u.id as user_id, u.username, u.email 
            FROM password_resets pr 
            JOIN users u ON pr.user_id = u.id 
            WHERE pr.token = ? AND pr.expires_at > NOW()
        ");
        $stmt->execute([$token]);
        $reset = $stmt->fetch();
        
        if (!$reset) {
            flash('error', 'Token de reset inválido o expirado.');
            redirect('login');
            return;
        }
        
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            validate_csrf();
            
            $password = $_POST['password'] ?? '';
            $password_confirm = $_POST['password_confirm'] ?? '';
            
            if (empty($password) || $password !== $password_confirm) {
                flash('error', 'Las contraseñas no coinciden.');
                redirect('auth/reset-password?token=' . urlencode($token));
                return;
            }
            
            // Validar fuerza de contraseña
            $password_strength = validate_password_strength($password);
            if ($password_strength !== true) {
                flash('error', $password_strength);
                redirect('auth/reset-password?token=' . urlencode($token));
                return;
            }
            
            // Actualizar contraseña
            $hash = password_hash($password, PASSWORD_BCRYPT);
            $update = $db->prepare("UPDATE users SET password_hash = ? WHERE id = ?");
            $update->execute([$hash, $reset['user_id']]);
            
            // Eliminar token
            $db->prepare("DELETE FROM password_resets WHERE token = ?")->execute([$token]);
            
            // Limpiar intentos fallidos
            SecurityHelper::clearFailedAttempts($db, $reset['email'], true);
            SecurityHelper::clearFailedAttempts($db, get_client_ip(), false);
            
            SecurityHelper::logSecurityEvent($db, 'password_reset_success', null, $reset['user_id']);
            
            flash('success', 'Contraseña actualizada correctamente. Ya puedes iniciar sesión.');
            redirect('login');
        }
        
        view('auth/reset-password', ['token' => $token]);
    }

    private static function sendVerificationEmail($email, $token, $username) {
        // En una implementación real, aquí enviarías un email
        $verification_url = "./?r=auth/verify-email&token=" . urlencode($token);
        
        // Simulación - en producción usarías PHPMailer o similar
        error_log("Verification email for $username ($email): $verification_url");
        
        return true;
    }

    private static function sendPasswordResetEmail($email, $token, $username) {
        // En una implementación real, aquí enviarías un email
        $reset_url = "./?r=auth/reset-password&token=" . urlencode($token);
        
        // Simulación - en producción usarías PHPMailer o similar
        error_log("Password reset email for $username ($email): $reset_url");
        
        return true;
    }

    public static function logout() {
        // Registrar logout
        if (!empty($_SESSION['user']['id'])) {
            global $CONFIG;
            try {
                $db = Database::getConnection($CONFIG);
                SecurityHelper::logSecurityEvent($db, 'logout', null, $_SESSION['user']['id']);
                
                // Actualizar last_active
                $db->prepare("UPDATE users SET last_active = NOW() WHERE id = ?")->execute([$_SESSION['user']['id']]);
            } catch (Exception $e) {
                error_log("Error during logout: " . $e->getMessage());
            }
        }
        
        session_destroy();
        redirect('/');
    }
}