<?php

namespace App\Http\Controllers\Admin;

use App\Core\Controller;
use App\Core\RateLimiter;
use App\Core\Request;
use App\Core\Response;
use App\Models\PasswordReset;
use App\Models\User;
use App\Services\Mailer;

class AuthController extends Controller
{
    // ─────────────────────────────────────────────────────────
    // Login / Logout
    // ─────────────────────────────────────────────────────────

    public function loginForm(Request $request, array $params = []): void
    {
        if ($this->auth()->check()) {
            Response::redirect('/admin/dashboard');
            return;
        }

        $view = $this->app->service('view');
        $html = $view->renderAdmin('auth/login', [
            'error'      => $this->session()->getFlash('login_error'),
            'reset_done' => $this->session()->getFlash('reset_done'),
            'csrf'       => $this->csrf(),
        ]);
        Response::html($html);
    }

    public function login(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $username   = trim($request->input('username', ''));
        $password   = $request->input('password', '');
        $rememberMe = (bool) $request->input('remember_me', false);

        // Rate limiting: key by IP + username to prevent brute-force
        $ip        = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
        $throttle  = new RateLimiter($this->app->basePath('storage/cache'));
        $throttleKey = 'login:' . $ip . ':' . strtolower($username);

        if ($throttle->isLocked($throttleKey)) {
            $remaining = $throttle->lockoutRemaining($throttleKey);
            $minutes   = (int) ceil($remaining / 60);
            $this->session()->flash('login_error', __('messages.login_locked', ['minutes' => $minutes]));
            Response::redirect('/admin/login');
            return;
        }

        if ($this->auth()->attempt($username, $password, $rememberMe)) {
            $throttle->clear($throttleKey);
            Response::redirect('/admin/dashboard');
        } else {
            $locked = $throttle->recordFailure($throttleKey);
            if ($locked) {
                $minutes = (int) ceil($throttle->lockoutRemaining($throttleKey) / 60);
                $this->session()->flash('login_error', __('messages.login_locked', ['minutes' => $minutes]));
            } else {
                $this->session()->flash('login_error', __('messages.login_error'));
            }
            Response::redirect('/admin/login');
        }
    }

    public function logout(Request $request, array $params = []): void
    {
        $this->auth()->logout();
        Response::redirect('/admin/login');
    }

    // ─────────────────────────────────────────────────────────
    // Forgot Password – step 1: request reset link
    // ─────────────────────────────────────────────────────────

    public function forgotPasswordForm(Request $request, array $params = []): void
    {
        if ($this->auth()->check()) {
            Response::redirect('/admin/dashboard');
            return;
        }

        $view = $this->app->service('view');
        $html = $view->renderAdmin('auth/forgot_password', [
            'success' => $this->session()->getFlash('reset_success'),
            'error'   => $this->session()->getFlash('reset_error'),
            'csrf'    => $this->csrf(),
        ]);
        Response::html($html);
    }

    public function forgotPasswordSend(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $email = trim($request->input('email', ''));

        // Validate email format
        if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $this->session()->flash('reset_error', __('messages.invalid_email'));
            Response::redirect('/admin/forgot-password');
            return;
        }

        // Opportunistic housekeeping: purge old expired tokens
        PasswordReset::purgeExpired();

        // Look up the user – but do NOT reveal whether the address exists.
        $user = User::findWhere(['email' => $email, 'is_active' => 1]);

        if ($user) {
            $token    = PasswordReset::createFor($email);
            $resetUrl = $this->buildResetUrl($token);
            $this->sendResetMail($email, $user['username'], $resetUrl);
        }

        // Always show the same success message regardless of whether the
        // address was found – prevents user enumeration attacks.
        $this->session()->flash(
            'reset_success',
            __('messages.reset_sent')
        );
        Response::redirect('/admin/forgot-password');
    }

    // ─────────────────────────────────────────────────────────
    // Reset Password – step 2: set new password via token link
    // ─────────────────────────────────────────────────────────

    public function resetPasswordForm(Request $request, array $params = []): void
    {
        if ($this->auth()->check()) {
            Response::redirect('/admin/dashboard');
            return;
        }

        $token  = trim($request->input('token', ''));
        $record = ($token !== '') ? PasswordReset::findValid($token) : null;

        $view = $this->app->service('view');
        $html = $view->renderAdmin('auth/reset_password', [
            'token' => $token,
            'valid' => $record !== null,
            'error' => $this->session()->getFlash('reset_pw_error'),
            'csrf'  => $this->csrf(),
        ]);
        Response::html($html);
    }

    public function resetPasswordSave(Request $request, array $params = []): void
    {
        $this->validateCsrf();

        $token    = trim($request->input('token', ''));
        $password = $request->input('password', '');
        $confirm  = $request->input('password_confirm', '');

        // Validate token
        $record = ($token !== '') ? PasswordReset::findValid($token) : null;
        if (!$record) {
            $this->session()->flash(
                'reset_pw_error',
                __('messages.reset_invalid_token')
            );
            Response::redirect('/admin/reset-password?token=' . urlencode($token));
            return;
        }

        // Validate new password length
        if (strlen($password) < 8) {
            $this->session()->flash('reset_pw_error', __('messages.password_min', ['min' => 8]));
            Response::redirect('/admin/reset-password?token=' . urlencode($token));
            return;
        }

        // Validate password confirmation
        if ($password !== $confirm) {
            $this->session()->flash('reset_pw_error', __('messages.password_mismatch'));
            Response::redirect('/admin/reset-password?token=' . urlencode($token));
            return;
        }

        // Find the user by the e-mail stored in the token record
        $user = User::findWhere(['email' => $record['email'], 'is_active' => 1]);
        if (!$user) {
            // Account deactivated between request and reset – treat as expired
            $this->session()->flash(
                'reset_pw_error',
                __('messages.reset_invalid_token')
            );
            Response::redirect('/admin/reset-password?token=' . urlencode($token));
            return;
        }

        // Update the password hash
        User::updateById((int) $user['id'], [
            'password_hash' => password_hash($password, PASSWORD_BCRYPT),
            'updated_at'    => date('Y-m-d H:i:s'),
        ]);

        // Invalidate all tokens for this address (single-use + cleanup)
        PasswordReset::deleteForEmail($record['email']);

        $this->session()->flash('reset_done', __('messages.reset_success'));
        Response::redirect('/admin/login');
    }

    // ─────────────────────────────────────────────────────────
    // Private helpers
    // ─────────────────────────────────────────────────────────

    private function buildResetUrl(string $token): string
    {
        $base = rtrim(config('base_url', ''), '/');

        // Detect base URL from server variables when config is not set
        if ($base === '') {
            $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
            $host   = $_SERVER['HTTP_HOST'] ?? 'localhost';
            $base   = $scheme . '://' . $host;
        }

        return $base . '/admin/reset-password?token=' . urlencode($token);
    }

    private function sendResetMail(string $email, string $username, string $resetUrl): void
    {
        $mailConfig = config('mail', []);
        $mailer     = new Mailer($mailConfig);

        $subject   = 'Password Reset – ITSWEBER CMS';
        $htmlBody  = $this->buildResetMailHtml($username, $resetUrl);
        $plainBody = $this->buildResetMailText($username, $resetUrl);

        $mailer->sendHtml($email, $subject, $htmlBody, $plainBody);
    }

    private function buildResetMailText(string $username, string $resetUrl): string
    {
        $ttl = (int) (PasswordReset::TOKEN_TTL / 60);
        return "Hello {$username},\n\n"
             . "You (or someone else) requested a password reset for your ITSWEBER CMS account.\n\n"
             . "Click the link below to set a new password (valid for {$ttl} minutes):\n"
             . "{$resetUrl}\n\n"
             . "If you did not request a password reset, you can safely ignore this e-mail.\n"
             . "Your password will not change.\n\n"
             . "– ITSWEBER CMS";
    }

    private function buildResetMailHtml(string $username, string $resetUrl): string
    {
        $ttl      = (int) (PasswordReset::TOKEN_TTL / 60);
        $safeUrl  = htmlspecialchars($resetUrl, ENT_QUOTES, 'UTF-8');
        $safeName = htmlspecialchars($username, ENT_QUOTES, 'UTF-8');

        return '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Password Reset</title></head>'
             . '<body style="font-family:Arial,sans-serif;background:#f4f4f4;margin:0;padding:20px;">'
             . '<div style="max-width:520px;margin:0 auto;background:#fff;border-radius:6px;padding:32px 36px;">'
             . '<h2 style="margin-top:0;color:#1a1a2e;">Password Reset</h2>'
             . "<p>Hello <strong>{$safeName}</strong>,</p>"
             . '<p>You requested a password reset for your ITSWEBER CMS account.</p>'
             . '<p style="margin:24px 0;">'
             . "<a href=\"{$safeUrl}\" style=\"display:inline-block;background:#4a6cf7;color:#fff;"
             . 'padding:12px 24px;border-radius:4px;text-decoration:none;font-weight:bold;">'
             . 'Reset my password</a></p>'
             . "<p style=\"color:#666;font-size:13px;\">This link is valid for <strong>{$ttl} minutes</strong>"
             . ' and can only be used once.</p>'
             . '<p style="color:#666;font-size:13px;">If you did not request a password reset, '
             . 'please ignore this e-mail. Your password will not change.</p>'
             . '<hr style="border:none;border-top:1px solid #eee;margin:24px 0;">'
             . '<p style="color:#999;font-size:12px;">ITSWEBER CMS – automated message, do not reply.</p>'
             . '</div></body></html>';
    }
}
