<?php

declare(strict_types=1);

namespace App\Controllers;

use Core\Auth;
use Core\Request;
use Core\Response;
use Core\Session;
use Core\Database;
use App\Helpers\ActivityLogger;

final class AuthController extends BaseController
{
    // ── Login Form ────────────────────────────────────────────────────────────

    public function loginForm(array $params = []): void
    {
        if (Auth::check()) {
            $this->redirect('/dashboard');
        }

        $this->view('auth.login', [
            'pageTitle' => 'Sign In',
        ], 'auth');
    }

    // ── Login Submit ──────────────────────────────────────────────────────────

    public function login(array $params = []): void
    {
        if (Auth::check()) {
            $this->redirect('/dashboard');
        }

        Request::verifyCsrf();

        $email    = trim(Request::post('email', ''));
        $password = Request::post('password', '');
        $remember = Request::bool('remember');

        // Basic validation
        if (!$email || !$password) {
            $this->flash('error', 'Email and password are required.');
            $this->redirect('/auth/login');
        }

        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $this->flash('error', 'Please enter a valid email address.');
            $this->redirect('/auth/login');
        }

        // Fetch user
        $user = $this->db->fetchOne(
            "SELECT u.*, r.name AS role_name
               FROM users u
               JOIN roles r ON r.id = u.role_id
              WHERE u.email = ?",
            [$email]
        );

        // Account not found
        if (!$user) {
            $this->logFailedAttempt($email);
            $this->flash('error', 'Invalid email or password.');
            $this->redirect('/auth/login');
        }

        // Account inactive
        if (!(bool) $user['is_active']) {
            $this->flash('error', 'Your account has been deactivated. Please contact an administrator.');
            $this->redirect('/auth/login');
        }

        // Lockout check
        if ($user['locked_until'] && strtotime($user['locked_until']) > time()) {
            $remaining = ceil((strtotime($user['locked_until']) - time()) / 60);
            $this->flash('error', "Account locked due to too many failed attempts. Try again in {$remaining} minute(s).");
            $this->redirect('/auth/login');
        }

        // Wrong password
        if (!password_verify($password, $user['password_hash'])) {
            $this->handleFailedLogin($user);
            $this->flash('error', 'Invalid email or password.');
            $this->redirect('/auth/login');
        }

        // ── Success ───────────────────────────────────────────────────────────

        // Reset failed attempts
        $this->db->update('users', [
            'login_attempts' => 0,
            'locked_until'   => null,
            'last_login'     => date('Y-m-d H:i:s'),
        ], ['id' => $user['id']]);

        Auth::login($user);
        ActivityLogger::login($email);

        // Extend session for "remember me"
        if ($remember) {
            ini_set('session.cookie_lifetime', (string)(86400 * 30));
        }

        $redirect = Session::getFlash('redirect_after_login') ?? '/dashboard';
        $this->redirect($redirect);
    }

    // ── Logout ────────────────────────────────────────────────────────────────

    public function logout(array $params = []): void
    {
        $name = Auth::user()['name'] ?? 'Unknown';
        ActivityLogger::logout($name);
        Auth::logout();
        $this->redirect('/auth/login');
    }

    // ── Internals ─────────────────────────────────────────────────────────────

    private function handleFailedLogin(array $user): void
    {
        $attempts = (int) $user['login_attempts'] + 1;
        $data     = ['login_attempts' => $attempts];

        if ($attempts >= LOGIN_MAX_ATTEMPTS) {
            $data['locked_until'] = date('Y-m-d H:i:s', time() + LOGIN_LOCKOUT_MINUTES * 60);
        }

        $this->db->update('users', $data, ['id' => $user['id']]);
    }

    private function logFailedAttempt(string $email): void
    {
        // Rate-limit by IP for unknown emails (stored in session)
        $key      = 'login_fail_' . md5(Request::ip());
        $attempts = (int) Session::get($key, 0) + 1;
        Session::set($key, $attempts);
    }
}
