<?php
namespace App\Controllers;

use Core\Controller;
use App\Models\UserModel;
use App\Helpers\Helper;

class AuthController extends Controller
{
    private UserModel $userModel;

    public function __construct()
    {
        parent::__construct();
        $this->userModel = new UserModel();
    }

    public function loginForm(): void
    {
        if (isset($_SESSION['user_id'])) {
            $this->redirectByRole($_SESSION['user_role']);
        }
        $this->view('auth.login', ['title' => 'Login - ' . APP_NAME], 'auth');
    }

    public function login(): void
    {
        $this->verifyCsrf();
        $email    = filter_var($this->input('email', ''), FILTER_SANITIZE_EMAIL);
        $password = $this->input('password', '');
        $remember = $this->input('remember');

        if (!$email || !$password) {
            Helper::setFlash('danger', 'Email and password are required.');
            $this->redirect(APP_URL . '/login');
            return;
        }

        $user = $this->userModel->findByEmail($email);

        // Check lockout
        if ($user && $user['locked_until'] && strtotime($user['locked_until']) > time()) {
            Helper::setFlash('danger', 'Account locked. Try again after ' . Helper::datetime($user['locked_until']));
            $this->logLogin($user['id'], $email, 'blocked');
            $this->redirect(APP_URL . '/login');
            return;
        }

        if (!$user || !password_verify($password, $user['password'])) {
            if ($user) {
                $attempts = $user['login_attempts'] + 1;
                $lockUntil = $attempts >= MAX_LOGIN_ATTEMPTS ? date('Y-m-d H:i:s', time() + LOCKOUT_DURATION) : null;
                $this->userModel->update($user['id'], ['login_attempts' => $attempts, 'locked_until' => $lockUntil]);
            }
            $this->logLogin($user['id'] ?? null, $email, 'failed');
            Helper::setFlash('danger', 'Invalid email or password.');
            $this->redirect(APP_URL . '/login');
            return;
        }

        if ($user['status'] !== 'active') {
            Helper::setFlash('danger', 'Your account is ' . $user['status'] . '. Contact administrator.');
            $this->redirect(APP_URL . '/login');
            return;
        }

        // Successful login
        $this->userModel->update($user['id'], [
            'login_attempts' => 0,
            'locked_until'   => null,
            'last_login_at'  => date('Y-m-d H:i:s'),
            'last_login_ip'  => $_SERVER['REMOTE_ADDR'] ?? null,
        ]);

        session_regenerate_id(true);
        $_SESSION['user_id']    = $user['id'];
        $_SESSION['user_name']  = $user['first_name'] . ' ' . $user['last_name'];
        $_SESSION['user_email'] = $user['email'];
        $_SESSION['user_role']  = $user['role_name'];
        $_SESSION['user_role_id'] = $user['role_id'];
        $_SESSION['user_avatar'] = $user['avatar'];

        if ($remember) {
            $token = bin2hex(random_bytes(32));
            $this->userModel->update($user['id'], ['remember_token' => hash('sha256', $token)]);
            setcookie('remember_token', $token, time() + (30 * 86400), '/', '', false, true);
        }

        $this->logLogin($user['id'], $email, 'success');
        Helper::setFlash('success', 'Welcome back, ' . $user['first_name'] . '!');
        $this->redirectByRole($user['role_name']);
    }

    public function logout(): void
    {
        $userId = $_SESSION['user_id'] ?? null;
        session_unset();
        session_destroy();
        if (isset($_COOKIE['remember_token'])) {
            setcookie('remember_token', '', time() - 3600, '/');
            if ($userId) $this->userModel->update($userId, ['remember_token' => null]);
        }
        $this->redirect(APP_URL . '/');
    }

    public function registerForm(): void
    {
        $this->view('auth.register', ['title' => 'Register - ' . APP_NAME], 'auth');
    }

    public function register(): void
    {
        $this->verifyCsrf();
        $data = [
            'first_name' => Helper::sanitize($this->input('first_name', '')),
            'last_name'  => Helper::sanitize($this->input('last_name', '')),
            'email'      => filter_var($this->input('email', ''), FILTER_SANITIZE_EMAIL),
            'phone'      => Helper::sanitize($this->input('phone', '')),
            'password'   => $this->input('password', ''),
            'confirm'    => $this->input('confirm_password', ''),
        ];

        $errors = [];
        if (!$data['first_name']) $errors[] = 'First name is required.';
        if (!$data['email'] || !filter_var($data['email'], FILTER_VALIDATE_EMAIL)) $errors[] = 'Valid email is required.';
        if (strlen($data['password']) < PASSWORD_MIN_LENGTH) $errors[] = 'Password must be at least ' . PASSWORD_MIN_LENGTH . ' characters.';
        if ($data['password'] !== $data['confirm']) $errors[] = 'Passwords do not match.';
        if ($this->userModel->findByEmail($data['email'])) $errors[] = 'Email already registered.';

        if ($errors) {
            Helper::setFlash('danger', implode('<br>', $errors));
            $this->redirect(APP_URL . '/register');
            return;
        }

        $token = bin2hex(random_bytes(32));

        $userId = $this->userModel->create([
            'role_id'            => 7,
            'first_name'         => $data['first_name'],
            'last_name'          => $data['last_name'],
            'email'              => $data['email'],
            'phone'              => $data['phone'],
            'password'           => password_hash($data['password'], PASSWORD_BCRYPT, ['cost' => 12]),
            'status'             => 'pending',
            'verification_token' => hash('sha256', $token),
        ]);

        // Send welcome + verification email
        $this->sendWelcomeMail($data['email'], $data['first_name'], $token);

        $this->view('auth.registered', [
            'title' => 'Check Your Email',
            'email' => $data['email'],
            'name'  => $data['first_name'],
        ], 'auth');
    }

    public function verifyEmail(string $token): void
    {
        $hashed = hash('sha256', $token);

        // Find user by token regardless of status
        $user = $this->db->fetch(
            "SELECT * FROM users WHERE verification_token = ? LIMIT 1",
            [$hashed]
        );

        // If token not found, check if already verified (link clicked twice)
        if (!$user) {
            Helper::setFlash('info', 'This verification link has already been used or has expired. If you are already registered, please <a href="'.APP_URL.'/login">log in</a>. Need a new link? <a href="'.APP_URL.'/resend-verification">Resend verification email</a>.');
            $this->redirect(APP_URL . '/login');
            return;
        }

        // Already active — just log them in
        if ($user['status'] === 'active' && !empty($user['email_verified_at'])) {
            session_regenerate_id(true);
            $_SESSION['user_id']      = $user['id'];
            $_SESSION['user_name']    = $user['first_name'] . ' ' . $user['last_name'];
            $_SESSION['user_email']   = $user['email'];
            $_SESSION['user_role']    = 'tenant';
            $_SESSION['user_role_id'] = $user['role_id'];
            $_SESSION['user_avatar']  = $user['avatar'];
            Helper::setFlash('info', 'Your email is already verified. Welcome back, ' . $user['first_name'] . '!');
            $this->redirect(APP_URL . '/tenant');
            return;
        }

        // Activate account
        $this->userModel->update($user['id'], [
            'status'             => 'active',
            'email_verified_at'  => date('Y-m-d H:i:s'),
            'verification_token' => null,
        ]);

        // Auto-login
        session_regenerate_id(true);
        $_SESSION['user_id']    = $user['id'];
        $_SESSION['user_name']  = $user['first_name'] . ' ' . $user['last_name'];
        $_SESSION['user_email'] = $user['email'];
        $_SESSION['user_role']  = 'tenant';
        $_SESSION['user_role_id'] = $user['role_id'];
        $_SESSION['user_avatar']  = $user['avatar'];

        Helper::setFlash('success', 'Welcome, ' . $user['first_name'] . '! Your account is now active. You can make a booking below.');
        $this->redirect(APP_URL . '/tenant');
    }

    public function resendVerificationForm(): void
    {
        $this->view('auth.resend-verification', ['title' => 'Resend Verification Email'], 'auth');
    }

    public function resendVerification(): void
    {
        $this->verifyCsrf();
        $email = filter_var($this->input('email', ''), FILTER_SANITIZE_EMAIL);

        if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
            Helper::setFlash('danger', 'Please enter a valid email address.');
            $this->redirect(APP_URL . '/resend-verification');
            return;
        }

        $user = $this->db->fetch("SELECT * FROM users WHERE email = ? LIMIT 1", [$email]);

        if ($user && $user['status'] === 'active' && !empty($user['email_verified_at'])) {
            Helper::setFlash('info', 'Your email is already verified. Please <a href="'.APP_URL.'/login">log in</a>.');
            $this->redirect(APP_URL . '/login');
            return;
        }

        if ($user && $user['status'] === 'pending') {
            $token = bin2hex(random_bytes(32));
            $this->userModel->update($user['id'], ['verification_token' => hash('sha256', $token)]);
            $this->sendWelcomeMail($user['email'], $user['first_name'], $token);
        }

        // Always show success to prevent email enumeration
        Helper::setFlash('success', 'If that email is registered and unverified, a new verification link has been sent. Please check your inbox.');
        $this->redirect(APP_URL . '/resend-verification');
    }

    private function sendWelcomeMail(string $to, string $name, string $token): void
    {
        $rows = $this->db->fetchAll("SELECT `key`, value FROM settings WHERE `group`='email'");
        $cfg  = [];
        foreach ($rows as $r) { $cfg[$r['key']] = $r['value']; }

        $host     = trim($cfg['smtp_host']       ?? '');
        $port     = (int)($cfg['smtp_port']       ?? 587);
        $user     = trim($cfg['smtp_username']    ?? '');
        $pass     = $cfg['smtp_password']          ?? '';
        $from     = trim($cfg['mail_from_address'] ?? $user);
        $fromName = trim($cfg['mail_from_name']    ?? APP_NAME);
        $enc      = strtolower(trim($cfg['smtp_encryption'] ?? ($port == 465 ? 'ssl' : 'tls')));

        if (!$host || !$user || !$pass) return; // silently skip if SMTP not configured

        $verifyUrl = APP_URL . '/verify-email/' . $token;
        $appName   = APP_NAME;
        $year      = date('Y');

        $html = <<<HTML
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body style="margin:0;padding:0;background:#f0f4f8;font-family:'Segoe UI',Arial,sans-serif">
<table width="100%" cellpadding="0" cellspacing="0" style="background:#f0f4f8;padding:40px 0">
<tr><td align="center">
<table width="600" cellpadding="0" cellspacing="0" style="background:#fff;border-radius:16px;overflow:hidden;box-shadow:0 4px 24px rgba(0,0,0,.10)">
  <!-- Header -->
  <tr><td style="background:linear-gradient(135deg,#1a3c5e,#2d6a9f);padding:40px;text-align:center">
    <h1 style="color:#fff;margin:0;font-size:28px;font-weight:800">{$appName}</h1>
    <p style="color:rgba(255,255,255,.8);margin:8px 0 0;font-size:14px">Premium Residence Management</p>
  </td></tr>
  <!-- Welcome banner -->
  <tr><td style="background:#e8f4fd;padding:20px 40px;text-align:center;border-bottom:1px solid #d0e8f7">
    <span style="font-size:48px">🎉</span>
    <h2 style="color:#1a3c5e;margin:8px 0 0;font-size:22px">Welcome, {$name}!</h2>
  </td></tr>
  <!-- Body -->
  <tr><td style="padding:40px">
    <p style="color:#374151;font-size:16px;line-height:1.7;margin:0 0 20px">
      Thank you for registering with <strong>{$appName}</strong>. We're thrilled to have you on board!
    </p>
    <p style="color:#374151;font-size:15px;line-height:1.7;margin:0 0 30px">
      To activate your account and start exploring our available units, please verify your email address by clicking the button below.
    </p>
    <!-- CTA Button -->
    <table width="100%" cellpadding="0" cellspacing="0">
    <tr><td align="center" style="padding:10px 0 30px">
      <a href="{$verifyUrl}"
         style="background:linear-gradient(135deg,#1a3c5e,#2d6a9f);color:#fff;text-decoration:none;padding:16px 48px;border-radius:50px;font-size:16px;font-weight:700;display:inline-block;letter-spacing:.5px">
        ✅ Verify My Email &amp; Sign In
      </a>
    </td></tr>
    </table>
    <!-- What's next -->
    <div style="background:#f8fafc;border-radius:12px;padding:24px;margin:0 0 24px">
      <h3 style="color:#1a3c5e;margin:0 0 16px;font-size:16px">What happens next?</h3>
      <table cellpadding="0" cellspacing="0" width="100%">
        <tr>
          <td width="32" valign="top" style="padding:4px 0"><span style="background:#1a3c5e;color:#fff;border-radius:50%;width:24px;height:24px;display:inline-block;text-align:center;line-height:24px;font-size:12px;font-weight:700">1</span></td>
          <td style="padding:4px 0 4px 12px;color:#374151;font-size:14px">Click the button above to verify your email</td>
        </tr>
        <tr>
          <td width="32" valign="top" style="padding:4px 0"><span style="background:#1a3c5e;color:#fff;border-radius:50%;width:24px;height:24px;display:inline-block;text-align:center;line-height:24px;font-size:12px;font-weight:700">2</span></td>
          <td style="padding:4px 0 4px 12px;color:#374151;font-size:14px">You'll be signed in automatically to your portal</td>
        </tr>
        <tr>
          <td width="32" valign="top" style="padding:4px 0"><span style="background:#1a3c5e;color:#fff;border-radius:50%;width:24px;height:24px;display:inline-block;text-align:center;line-height:24px;font-size:12px;font-weight:700">3</span></td>
          <td style="padding:4px 0 4px 12px;color:#374151;font-size:14px">Browse properties and make a booking</td>
        </tr>
      </table>
    </div>
    <p style="color:#9ca3af;font-size:13px;margin:0">
      If you didn't create this account, you can safely ignore this email.<br>
      This link expires in <strong>24 hours</strong>.
    </p>
    <hr style="border:none;border-top:1px solid #e5e7eb;margin:24px 0">
    <p style="color:#9ca3af;font-size:12px;margin:0">
      Can't click the button? Copy and paste this link into your browser:<br>
      <a href="{$verifyUrl}" style="color:#2d6a9f;font-size:11px;word-break:break-all">{$verifyUrl}</a>
    </p>
  </td></tr>
  <!-- Footer -->
  <tr><td style="background:#f8fafc;padding:24px 40px;text-align:center;border-top:1px solid #e5e7eb">
    <p style="color:#9ca3af;font-size:12px;margin:0">&copy; {$year} {$appName}. All rights reserved.</p>
  </td></tr>
</table>
</td></tr>
</table>
</body>
</html>
HTML;

        $plain = "Welcome, {$name}!\n\nThank you for registering with {$appName}.\n\nPlease verify your email by visiting:\n{$verifyUrl}\n\nThis link expires in 24 hours.\n\n-- {$appName}";

        try {
            $ctx = stream_context_create(['ssl' => [
                'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true,
            ]]);
            $socketAddr = ($enc === 'ssl' ? 'ssl://' : '') . $host . ':' . $port;
            $sock = @stream_socket_client($socketAddr, $errno, $errstr, 15, STREAM_CLIENT_CONNECT, $ctx);
            if (!$sock) return;
            stream_set_timeout($sock, 15);

            $recv = function() use ($sock): string {
                $resp = '';
                while ($line = fgets($sock, 515)) {
                    $resp .= $line;
                    if (substr($line, 3, 1) === ' ') break;
                }
                return $resp;
            };
            $send = fn(string $cmd) => fwrite($sock, $cmd . "\r\n");

            $recv(); // 220 greeting
            $send('EHLO ' . (gethostname() ?: 'localhost'));
            $recv();
            if ($enc === 'tls') {
                $send('STARTTLS'); $recv();
                stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
                $send('EHLO ' . (gethostname() ?: 'localhost')); $recv();
            }
            $send('AUTH LOGIN'); $recv();
            $send(base64_encode($user)); $recv();
            $send(base64_encode($pass)); $recv();
            $send("MAIL FROM:<{$from}>"); $recv();
            $send("RCPT TO:<{$to}>"); $recv();
            $send('DATA'); $recv();

            $date     = date('r');
            $msgId    = '<welcome.' . time() . '@' . str_replace('mail.', '', $host) . '>';
            $boundary = 'wb_' . md5($token);
            $subject  = 'Welcome to ' . $appName . ' - Verify Your Email';

            $send(
                "Date: {$date}\r\nMessage-ID: {$msgId}\r\n" .
                "From: {$fromName} <{$from}>\r\nReply-To: {$from}\r\nTo: {$to}\r\n" .
                "Subject: {$subject}\r\nMIME-Version: 1.0\r\n" .
                "Content-Type: multipart/alternative; boundary=\"{$boundary}\"\r\n" .
                "X-Mailer: Zabibu-Residence-Mailer\r\n\r\n" .
                "--{$boundary}\r\nContent-Type: text/plain; charset=UTF-8\r\n" .
                "Content-Transfer-Encoding: base64\r\n\r\n" .
                chunk_split(base64_encode($plain)) .
                "--{$boundary}\r\nContent-Type: text/html; charset=UTF-8\r\n" .
                "Content-Transfer-Encoding: base64\r\n\r\n" .
                chunk_split(base64_encode($html)) .
                "--{$boundary}--\r\n."
            );
            $recv();
            $send('QUIT');
            fclose($sock);
        } catch (\Throwable $e) {
            // Silently fail — account still created
        }
    }

    public function forgotForm(): void
    {
        $this->view('auth.forgot', ['title' => 'Forgot Password'], 'auth');
    }

    public function forgot(): void
    {
        $email = filter_var($this->input('email', ''), FILTER_SANITIZE_EMAIL);
        $user = $this->userModel->findByEmail($email);
        if ($user) {
            $token = bin2hex(random_bytes(32));
            $expires = date('Y-m-d H:i:s', time() + 3600);
            $this->userModel->update($user['id'], [
                'password_reset_token'   => hash('sha256', $token),
                'password_reset_expires' => $expires,
            ]);
        }
        Helper::setFlash('success', 'If that email exists, a reset link has been sent.');
        $this->redirect(APP_URL . '/forgot-password');
    }

    public function resetForm(string $token): void
    {
        $this->view('auth.reset', ['title' => 'Reset Password', 'token' => $token], 'auth');
    }

    public function reset(): void
    {
        $token    = $this->input('token', '');
        $password = $this->input('password', '');
        $confirm  = $this->input('confirm_password', '');

        if ($password !== $confirm || strlen($password) < PASSWORD_MIN_LENGTH) {
            Helper::setFlash('danger', 'Invalid password.');
            $this->back();
            return;
        }

        $hashed = hash('sha256', $token);
        $user = $this->db->fetch("SELECT * FROM users WHERE password_reset_token = ? AND password_reset_expires > NOW()", [$hashed]);
        if (!$user) {
            Helper::setFlash('danger', 'Invalid or expired reset token.');
            $this->redirect(APP_URL . '/forgot-password');
            return;
        }

        $this->userModel->update($user['id'], [
            'password'               => password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]),
            'password_reset_token'   => null,
            'password_reset_expires' => null,
        ]);

        Helper::setFlash('success', 'Password reset successfully. Please login.');
        $this->redirect(APP_URL . '/login');
    }

    private function redirectByRole(string $role): void
    {
        match ($role) {
            'super_admin', 'property_owner', 'property_manager', 'accountant', 'receptionist'
                => $this->redirect(APP_URL . '/admin'),
            'tenant' => $this->redirect(APP_URL . '/tenant'),
            default  => $this->redirect(APP_URL . '/'),
        };
    }

    private function logLogin(?int $userId, string $email, string $status): void
    {
        $this->db->insert('login_logs', [
            'user_id'    => $userId,
            'email'      => $email,
            'ip_address' => $_SERVER['REMOTE_ADDR'] ?? null,
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null,
            'status'     => $status,
        ]);
    }
}
