<?php
namespace App\Controllers;

use App\Core\Controller;
use App\Core\Database;
use App\Core\Auth;
use App\Core\MobileLicenseManager;
use App\Core\TOTP;
use PDO;

class AuthController extends Controller
{

    private function verifyUserPassword(array $user, string $password): bool
    {
        $hash = '';
        if (!empty($user['password'] ?? null)) {
            $hash = (string)$user['password'];
        } elseif (!empty($user['password'] ?? null)) {
            $hash = (string)$user['password'];
        }

        if ($hash === '') {
            return false;
        }

        // Si c'est un hash (bcrypt/argon), utiliser password_verify.
        if (str_starts_with($hash, '$2y$') || str_starts_with($hash, '$2a$') || str_starts_with($hash, '$argon2')) {
            return password_verify($password, $hash);
        }

        // Fallback legacy: comparaison directe (évite de bloquer un env qui stocke en clair)
        return hash_equals($hash, $password);
    }

    public function login(): void
    {
        // Si déjà authentifié, rediriger vers le tableau de bord
        if (Auth::check() && ($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'GET') {
            $this->redirect('/dashboard');
            return;
        }

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            // Accepter email ou username
            $identifier = trim($_POST['email'] ?? $_POST['username'] ?? '');
            $password = $_POST['password'] ?? '';
            
            // Vérifier si c'est une requête AJAX
            $isAjax = !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && 
                      strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
            $isAjax = $isAjax || (isset($_SERVER['HTTP_ACCEPT']) && strpos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false);
            
            $pdo = Database::pdo();
            // Chercher par email, et aussi par username si la colonne existe
            $hasUsername = false;
            try {
                $hasUsername = (bool)$pdo->query("SHOW COLUMNS FROM users LIKE 'username'")->fetch();
            } catch (\Throwable $e) {
                $hasUsername = false;
            }

            if ($hasUsername) {
                $stmt = $pdo->prepare('SELECT * FROM users WHERE (email = :id OR username = :id) AND active = 1 LIMIT 1');
            } else {
                $stmt = $pdo->prepare('SELECT * FROM users WHERE email = :id AND active = 1 LIMIT 1');
            }
            $stmt->execute(['id' => $identifier]);
            $user = $stmt->fetch(PDO::FETCH_ASSOC);

            if ($user && $this->verifyUserPassword($user, (string)$password)) {
                // 2FA check if enabled
                if (!empty($user['totp_secret'])) {
                    if ($isAjax) {
                        header('Content-Type: application/json');
                        echo json_encode(['success' => false, 'requires_2fa' => true]);
                        return;
                    }
                    // Ask for 2FA code
                    $_SESSION['2fa_user'] = $user; // temp store
                    $this->view('auth/2fa', ['_layout' => 'auth']);
                    return;
                }
                $this->touchLastLogin($pdo, $user);
                Auth::login($this->publicUser($user));
                
                if ($isAjax) {
                    header('Content-Type: application/json');
                    echo json_encode(['success' => true, 'redirect' => '/dashboard']);
                    return;
                }
                $this->redirect('/dashboard');
            }
            
            if ($isAjax) {
                header('Content-Type: application/json');
                http_response_code(401);
                echo json_encode(['success' => false, 'message' => 'Identifiants invalides']);
                return;
            }
            
            $this->view('auth/login', ['error' => 'Identifiants invalides', '_layout' => 'auth']);
            return;
        }
    $this->view('auth/login', ['_layout' => 'auth']);
    }

    public function verify2fa(): void
    {
        $user = $_SESSION['2fa_user'] ?? null;
        if (!$user) { $this->redirect('/login'); }

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $code = trim($_POST['code'] ?? '');
            if ($code && TOTP::verify($user['totp_secret'], $code)) {
                unset($_SESSION['2fa_user']);
                $pdo = Database::pdo();
                $this->touchLastLogin($pdo, $user);
                Auth::login($this->publicUser($user));
                $this->redirect('/dashboard');
                return;
            }
            $this->view('auth/2fa', ['error' => 'Code invalide', '_layout' => 'auth']);
            return;
        }
    $this->view('auth/2fa', ['_layout' => 'auth']);
    }

    public function logout(): void
    {
        Auth::logout();
        $this->redirect('/login');
    }

    private function publicUser(array $u): array
    {
        $roleKey = (string)($u['role_key'] ?? 'user');
        $technicianType = strtolower(trim((string)($u['technician_type'] ?? '')));
        if (in_array($roleKey, ['agent', 'superviseur', 'supervisor'], true) && in_array($technicianType, ['etude', 'raccordement'], true)) {
            $technicianType = 'etude_raccordement';
        }

        return [
            'id' => $u['id'],
            'name' => $u['name'],
            'email' => $u['email'],
            'role_key' => $roleKey,
            'technician_type' => $technicianType !== '' ? $technicianType : null,
            'assigned_city' => trim((string)($u['assigned_city'] ?? '')) ?: null,
        ];
    }

    private function touchLastLogin(PDO $pdo, array $user): void
    {
        $userId = (int)($user['id'] ?? 0);
        if ($userId <= 0) {
            return;
        }

        try {
            MobileLicenseManager::updateUserLastLogin($pdo, $userId, 'web');
        } catch (\Throwable $e) {
        }
    }
}
