<?php
namespace App\Controllers;

use App\Core\Controller;
use App\Core\Database;
use App\Core\SmtpMailer;

class AuthController extends Controller
{
    protected function db()
    {
        return Database::getInstance();
    }

    private function startSession(): void
    {
        if (session_status() !== PHP_SESSION_ACTIVE) {
            session_start();
        }
    }

    public function login()
    {
        $this->startSession();

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $email = trim($_POST['email'] ?? '');
            $password = (string)($_POST['password'] ?? '');

            $stmt = $this->db()->prepare("
                SELECT u.*, r.code AS role_code
                FROM users u
                LEFT JOIN roles r ON r.id = u.role_id
                WHERE u.email = ?
                LIMIT 1
            ");
            $stmt->execute([$email]);
            $user = $stmt->fetch(\PDO::FETCH_ASSOC);

            if (!$user || empty($user['password_hash']) || !password_verify($password, $user['password_hash'])) {
                $_SESSION['error'] = "Invalid credentials.";
                header("Location: /easychair/login");
                exit;
            }

            if (isset($user['is_active']) && (int)$user['is_active'] !== 1) {
                $_SESSION['error'] = "Account is disabled.";
                header("Location: /easychair/login");
                exit;
            }

            $_SESSION['user_id'] = (int)$user['id'];
            $_SESSION['user_name'] = trim(($user['first_name'] ?? '') . ' ' . ($user['last_name'] ?? ''));
            $_SESSION['email'] = $user['email'];
            $_SESSION['role_id'] = (int)($user['role_id'] ?? 0);
            $_SESSION['role'] = (string)($user['role_code'] ?? 'author');
            $_SESSION['user_role'] = $_SESSION['role'];
            $_SESSION['org_id'] = (int)($user['org_id'] ?? 0);

            $stmt = $this->db()->prepare("
                SELECT conference_id
                FROM user_conferences
                WHERE user_id = ?
                ORDER BY conference_id DESC
            ");
            $stmt->execute([(int)$user['id']]);
            $_SESSION['conference_list'] = array_map('intval', $stmt->fetchAll(\PDO::FETCH_COLUMN));

            if (count($_SESSION['conference_list']) === 1) {
                $_SESSION['conference_id'] = (int)$_SESSION['conference_list'][0];

                $stmt = $this->db()->prepare("SELECT org_id FROM conferences WHERE id=? LIMIT 1");
                $stmt->execute([(int)$_SESSION['conference_id']]);
                $_SESSION['org_id'] = (int)$stmt->fetchColumn();

                if (in_array($_SESSION['role'], ['super_admin','org_admin','admin','organizer','conference_chair','track_chair'], true)) {
                    header("Location: /easychair/admin/dashboard");
                    exit;
                }

                if ($_SESSION['role'] === 'reviewer') {
                    header("Location: /easychair/reviewer/dashboard");
                    exit;
                }

                header("Location: /easychair/author/dashboard");
                exit;
            }

            header("Location: /easychair/select-conference");
            exit;
        }

        require BASE_PATH . '/app/views/auth/login.php';
    }

    public function register()
    {
        $this->startSession();

        $db = $this->db();

        $preselectedSlug = trim((string)($_GET['conference'] ?? $_POST['conference_slug'] ?? ''));
        $preselectedConference = null;

        if ($preselectedSlug !== '') {
            $stmt = $db->prepare("
                SELECT c.*, o.name AS org_name
                FROM conferences c
                LEFT JOIN organizations o ON o.id = c.org_id
                LEFT JOIN org_conference_policy p ON p.org_id = c.org_id
                WHERE c.slug = ?
                  AND c.status IN ('open','reviewing','decision')
                  AND c.id = COALESCE(p.conference_id, c.id)
                LIMIT 1
            ");
            $stmt->execute([$preselectedSlug]);
            $preselectedConference = $stmt->fetch(\PDO::FETCH_ASSOC);
        }

        $stmt = $db->query("
            SELECT c.*, o.name AS org_name
            FROM conferences c
            LEFT JOIN organizations o ON o.id = c.org_id
            LEFT JOIN org_conference_policy p ON p.org_id = c.org_id
            WHERE c.status IN ('open','reviewing','decision')
              AND c.id = COALESCE(p.conference_id, c.id)
            ORDER BY o.name ASC, c.id DESC
        ");
        $conferences = $stmt->fetchAll(\PDO::FETCH_ASSOC);

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $firstName = trim($_POST['first_name'] ?? '');
            $lastName = trim($_POST['last_name'] ?? '');
            $email = strtolower(trim($_POST['email'] ?? ''));
            $phone = trim($_POST['phone'] ?? '');
            $password = (string)($_POST['password'] ?? '');
            $password2 = (string)($_POST['password_confirm'] ?? '');
            $conferenceId = (int)($_POST['conference_id'] ?? 0);
            $affiliation = trim($_POST['affiliation'] ?? '');

            if ($conferenceId <= 0 && !empty($preselectedConference['id'])) {
                $conferenceId = (int)$preselectedConference['id'];
            }

            if ($firstName === '' || $lastName === '' || $email === '' || $phone === '' || $password === '' || $conferenceId <= 0) {
                $_SESSION['error'] = "All required fields must be completed. Phone is compulsory.";
                header("Location: /easychair/register" . ($preselectedSlug ? "?conference=" . urlencode($preselectedSlug) : ""));
                exit;
            }

            if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
                $_SESSION['error'] = "Invalid email address.";
                header("Location: /easychair/register" . ($preselectedSlug ? "?conference=" . urlencode($preselectedSlug) : ""));
                exit;
            }

            if ($password !== $password2) {
                $_SESSION['error'] = "Password confirmation does not match.";
                header("Location: /easychair/register" . ($preselectedSlug ? "?conference=" . urlencode($preselectedSlug) : ""));
                exit;
            }

            if (strlen($password) < 8) {
                $_SESSION['error'] = "Password must be at least 8 characters.";
                header("Location: /easychair/register" . ($preselectedSlug ? "?conference=" . urlencode($preselectedSlug) : ""));
                exit;
            }

            $stmt = $db->prepare("
                SELECT c.*, p.conference_id AS current_conference_id
                FROM conferences c
                LEFT JOIN org_conference_policy p ON p.org_id = c.org_id
                WHERE c.id = ?
                LIMIT 1
            ");
            $stmt->execute([$conferenceId]);
            $conference = $stmt->fetch(\PDO::FETCH_ASSOC);

            if (!$conference) {
                $_SESSION['error'] = "Selected conference not found.";
                header("Location: /easychair/register" . ($preselectedSlug ? "?conference=" . urlencode($preselectedSlug) : ""));
                exit;
            }

            if (!in_array($conference['status'], ['open','reviewing','decision'], true)) {
                $_SESSION['error'] = "Selected conference is not open for author registration.";
                header("Location: /easychair/register" . ($preselectedSlug ? "?conference=" . urlencode($preselectedSlug) : ""));
                exit;
            }

            if (!empty($conference['current_conference_id']) && (int)$conference['current_conference_id'] !== $conferenceId) {
                $_SESSION['error'] = "Selected conference is not the current conference for this organization.";
                header("Location: /easychair/register" . ($preselectedSlug ? "?conference=" . urlencode($preselectedSlug) : ""));
                exit;
            }

            $stmt = $db->prepare("SELECT id FROM roles WHERE code='author' LIMIT 1");
            $stmt->execute();
            $authorRoleId = (int)$stmt->fetchColumn();

            if ($authorRoleId <= 0) {
                exit("Author role missing.");
            }

            $stmt = $db->prepare("SELECT id FROM users WHERE email=? LIMIT 1");
            $stmt->execute([$email]);
            $existingUserId = (int)$stmt->fetchColumn();

            if ($existingUserId > 0) {
                $userId = $existingUserId;

                $stmt = $db->prepare("
                    UPDATE users
                    SET first_name = COALESCE(NULLIF(?,''), first_name),
                        last_name = COALESCE(NULLIF(?,''), last_name),
                        phone = ?,
                        mobile = COALESCE(NULLIF(?,''), mobile),
                        org_id = ?,
                        role_id = COALESCE(role_id, ?),
                        is_active = 1
                    WHERE id = ?
                ");
                $stmt->execute([
                    $firstName,
                    $lastName,
                    $phone,
                    $phone,
                    (int)$conference['org_id'],
                    $authorRoleId,
                    $userId
                ]);
            } else {
                $stmt = $db->prepare("
                    INSERT INTO users
                    (org_id, role_id, first_name, last_name, email, password_hash, phone, mobile, preferred_lang, is_active, created_at)
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'en', 1, NOW())
                ");
                $stmt->execute([
                    (int)$conference['org_id'],
                    $authorRoleId,
                    $firstName,
                    $lastName,
                    $email,
                    password_hash($password, PASSWORD_BCRYPT),
                    $phone,
                    $phone
                ]);

                $userId = (int)$db->lastInsertId();
            }

            $stmt = $db->prepare("
                SELECT id
                FROM user_conferences
                WHERE user_id = ?
                  AND conference_id = ?
                LIMIT 1
            ");
            $stmt->execute([$userId, $conferenceId]);

            if (!$stmt->fetchColumn()) {
                $stmt = $db->prepare("
                    INSERT INTO user_conferences
                    (user_id, conference_id, role_id)
                    VALUES (?, ?, ?)
                ");
                $stmt->execute([$userId, $conferenceId, $authorRoleId]);
            }

            $_SESSION['user_id'] = $userId;
            $_SESSION['user_name'] = $firstName . ' ' . $lastName;
            $_SESSION['email'] = $email;
            $_SESSION['role_id'] = $authorRoleId;
            $_SESSION['role'] = 'author';
            $_SESSION['user_role'] = 'author';
            $_SESSION['conference_role'] = 'author';
            $_SESSION['conference_role_id'] = $authorRoleId;
            $_SESSION['conference_id'] = $conferenceId;
            $_SESSION['org_id'] = (int)$conference['org_id'];
            $_SESSION['conference_list'] = [$conferenceId];

            header("Location: /easychair/author/dashboard");
            exit;
        }

        require BASE_PATH . '/app/views/auth/register.php';
    }


    public function logout()
    {
        $this->startSession();
        session_destroy();
        header("Location: /easychair/login");
        exit;
    }

    private function renderSystemTemplate(string $key, array $vars = [], string $lang = 'en'): array
    {
        $stmt = $this->db()->prepare("
            SELECT *
            FROM system_email_templates
            WHERE template_key = ?
              AND is_active = 1
            LIMIT 1
        ");
        $stmt->execute([$key]);
        $tpl = $stmt->fetch(\PDO::FETCH_ASSOC);

        if (!$tpl) {
            return ['subject' => '', 'body' => ''];
        }

        $subject = $lang === 'ar'
            ? (($tpl['subject_ar'] ?? '') ?: ($tpl['subject_en'] ?? ''))
            : (($tpl['subject_en'] ?? '') ?: ($tpl['subject_ar'] ?? ''));

        $body = $lang === 'ar'
            ? (($tpl['body_ar'] ?? '') ?: ($tpl['body_en'] ?? ''))
            : (($tpl['body_en'] ?? '') ?: ($tpl['body_ar'] ?? ''));

        foreach ($vars as $k => $v) {
            $subject = str_replace('{' . $k . '}', (string)$v, $subject);
            $body = str_replace('{' . $k . '}', (string)$v, $body);
        }

        return ['subject' => $subject, 'body' => $body];
    }

    private function queueSystemMail(?int $userId, string $email, string $name, string $templateKey, string $subject, string $body): void
    {
        $stmt = $this->db()->prepare("
            INSERT INTO system_mail_outbox
            (template_key, user_id, recipient_email, recipient_name, subject, body, status)
            VALUES (?, ?, ?, ?, ?, ?, 'queued')
        ");
        $stmt->execute([$templateKey, $userId, $email, $name, $subject, $body]);

        $outboxId = (int)$this->db()->lastInsertId();

        $mailer = new SmtpMailer();
        $result = $mailer->send($email, $subject, $body, $name);

        if (!empty($result['ok'])) {
            $stmt = $this->db()->prepare("
                UPDATE system_mail_outbox
                SET status='sent',
                    sent_at=NOW(),
                    error_message=NULL
                WHERE id=?
            ");
            $stmt->execute([$outboxId]);
        } else {
            $stmt = $this->db()->prepare("
                UPDATE system_mail_outbox
                SET status='failed',
                    error_message=?
                WHERE id=?
            ");
            $stmt->execute([
                trim(($result['error'] ?? 'SMTP failed') . "\n\n" . ($result['debug'] ?? '')),
                $outboxId
            ]);
        }
    }

    public function forgotPassword()
    {
        $this->startSession();

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $email = strtolower(trim($_POST['email'] ?? ''));

            if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
                $_SESSION['error'] = "Please enter a valid email address.";
                header("Location: /easychair/forgot-password");
                exit;
            }

            $stmt = $this->db()->prepare("
                SELECT id, first_name, last_name, email, preferred_lang
                FROM users
                WHERE email = ?
                LIMIT 1
            ");
            $stmt->execute([$email]);
            $user = $stmt->fetch(\PDO::FETCH_ASSOC);

            /*
             * Always show generic success to avoid exposing accounts.
             */
            if ($user) {
                $token = bin2hex(random_bytes(32));
                $hash = password_hash($token, PASSWORD_BCRYPT);
                $expires = date('Y-m-d H:i:s', time() + 3600);

                $stmt = $this->db()->prepare("
                    INSERT INTO password_reset_tokens
                    (user_id, email, token_hash, expires_at, ip_address, user_agent)
                    VALUES (?, ?, ?, ?, ?, ?)
                ");
                $stmt->execute([
                    (int)$user['id'],
                    $email,
                    $hash,
                    $expires,
                    $_SERVER['REMOTE_ADDR'] ?? '',
                    substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 250)
                ]);

                $resetLink = 'https://www.jpu.edu.jo/easychair/reset-password?email=' . urlencode($email) . '&token=' . urlencode($token);
                $name = trim(($user['first_name'] ?? '') . ' ' . ($user['last_name'] ?? '')) ?: $email;

                $tpl = $this->renderSystemTemplate('password_reset', [
                    'user_name' => $name,
                    'reset_link' => $resetLink,
                    'expires_at' => $expires,
                ], ($user['preferred_lang'] ?? 'en'));

                $this->queueSystemMail(
                    (int)$user['id'],
                    $email,
                    $name,
                    'password_reset',
                    $tpl['subject'],
                    $tpl['body']
                );
            }

            $_SESSION['success'] = "If this email exists, a reset link has been sent.";
            header("Location: /easychair/forgot-password");
            exit;
        }

        require BASE_PATH . '/app/views/auth/forgot_password.php';
    }

    public function resetPassword()
    {
        $this->startSession();

        $email = strtolower(trim($_GET['email'] ?? $_POST['email'] ?? ''));
        $token = trim($_GET['token'] ?? $_POST['token'] ?? '');

        if ($email === '' || $token === '') {
            $_SESSION['error'] = "Invalid reset link.";
            header("Location: /easychair/forgot-password");
            exit;
        }

        $stmt = $this->db()->prepare("
            SELECT *
            FROM password_reset_tokens
            WHERE email = ?
              AND used_at IS NULL
              AND expires_at >= NOW()
            ORDER BY id DESC
            LIMIT 5
        ");
        $stmt->execute([$email]);
        $tokens = $stmt->fetchAll(\PDO::FETCH_ASSOC);

        $validRow = null;

        foreach ($tokens as $row) {
            if (password_verify($token, $row['token_hash'])) {
                $validRow = $row;
                break;
            }
        }

        if (!$validRow) {
            $_SESSION['error'] = "Reset link is invalid or expired.";
            header("Location: /easychair/forgot-password");
            exit;
        }

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $password = (string)($_POST['password'] ?? '');
            $confirm = (string)($_POST['password_confirm'] ?? '');

            if (strlen($password) < 8) {
                $_SESSION['error'] = "Password must be at least 8 characters.";
                header("Location: /easychair/reset-password?email=" . urlencode($email) . "&token=" . urlencode($token));
                exit;
            }

            if ($password !== $confirm) {
                $_SESSION['error'] = "Password confirmation does not match.";
                header("Location: /easychair/reset-password?email=" . urlencode($email) . "&token=" . urlencode($token));
                exit;
            }

            $stmt = $this->db()->prepare("
                UPDATE users
                SET password_hash = ?
                WHERE id = ?
            ");
            $stmt->execute([password_hash($password, PASSWORD_BCRYPT), (int)$validRow['user_id']]);

            $stmt = $this->db()->prepare("
                UPDATE password_reset_tokens
                SET used_at = NOW()
                WHERE id = ?
            ");
            $stmt->execute([(int)$validRow['id']]);

            $_SESSION['success'] = "Password changed successfully. Please login.";
            header("Location: /easychair/login");
            exit;
        }

        require BASE_PATH . '/app/views/auth/reset_password.php';
    }


}