<?php

namespace App\Core;

/**
 * ITSWEBER CMS – Authentication
 */
class Auth
{
    private Database $db;
    private Session $session;

    /** Remember-me cookie lifetime: 14 days (in seconds). */
    private const REMEMBER_TTL = 14 * 24 * 3600;

    /** Cookie name for remember-me token. */
    private const REMEMBER_COOKIE = 'iw_remember';

    public function __construct(Database $db, Session $session)
    {
        $this->db = $db;
        $this->session = $session;
    }

    /**
     * Attempt to log in a user.
     *
     * @param bool $remember  Issue a persistent remember-me cookie (14 days).
     */
    public function attempt(string $username, string $password, bool $remember = false): bool
    {
        $user = $this->db->fetch(
            "SELECT * FROM iw_users WHERE (username = :username OR email = :email) AND is_active = 1 LIMIT 1",
            [
                'username' => $username,
                'email' => $username,
            ]
        );

        if (!$user || !password_verify($password, $user['password_hash'])) {
            return false;
        }

        $this->session->regenerate();
        $this->session->set('user_id', $user['id']);
        $this->session->set('user_role', $user['role']);
        $this->session->set('user_name', $user['username']);

        if ($remember) {
            $this->issueRememberToken((int) $user['id']);
        }

        return true;
    }

    /**
     * Log out the current user.
     */
    public function logout(): void
    {
        $this->clearRememberToken();
        $this->session->remove('user_id');
        $this->session->remove('user_role');
        $this->session->remove('user_name');
        $this->session->regenerate();
    }

    /**
     * Check if a user is logged in (session or remember-me cookie).
     */
    public function check(): bool
    {
        if ($this->session->has('user_id')) {
            return true;
        }

        // Attempt auto-login from remember-me cookie
        return $this->loginFromRememberCookie();
    }

    /**
     * Get the current user ID.
     */
    public function userId(): ?int
    {
        return $this->session->get('user_id');
    }

    /**
     * Get the current user role.
     */
    public function role(): ?string
    {
        return $this->session->get('user_role');
    }

    /**
     * Check if the current user is an admin.
     */
    public function isAdmin(): bool
    {
        return $this->session->get('user_role') === 'admin';
    }

    /**
     * Get the current user's name.
     */
    public function userName(): ?string
    {
        return $this->session->get('user_name');
    }

    // ─────────────────────────────────────────────────────────
    // Remember-Me helpers (v3.0.4)
    // ─────────────────────────────────────────────────────────

    /**
     * Issue a remember-me token for the given user.
     *
     * Stores a hashed token in the DB and sets a cookie with the
     * plain-text selector:validator pair.
     */
    private function issueRememberToken(int $userId): void
    {
        $selector  = bin2hex(random_bytes(12));
        $validator = bin2hex(random_bytes(32));
        $hashedVal = hash('sha256', $validator);
        $expires   = date('Y-m-d H:i:s', time() + self::REMEMBER_TTL);

        // Ensure table exists (created by migration, but defensive)
        $this->db->query(
            "INSERT INTO iw_remember_tokens (user_id, selector, hashed_validator, expires_at) VALUES (:uid, :sel, :val, :exp)",
            ['uid' => $userId, 'sel' => $selector, 'val' => $hashedVal, 'exp' => $expires]
        );

        $cookieValue = $selector . ':' . $validator;
        $secure      = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');

        setcookie(self::REMEMBER_COOKIE, $cookieValue, [
            'expires'  => time() + self::REMEMBER_TTL,
            'path'     => '/admin',
            'secure'   => $secure,
            'httponly'  => true,
            'samesite' => 'Lax',
        ]);
    }

    /**
     * Attempt login from the remember-me cookie.
     */
    private function loginFromRememberCookie(): bool
    {
        $cookie = $_COOKIE[self::REMEMBER_COOKIE] ?? '';
        if ($cookie === '' || !str_contains($cookie, ':')) {
            return false;
        }

        [$selector, $validator] = explode(':', $cookie, 2);

        $row = $this->db->fetch(
            "SELECT rt.*, u.id AS uid, u.role, u.username, u.is_active
             FROM iw_remember_tokens rt
             JOIN iw_users u ON u.id = rt.user_id
             WHERE rt.selector = :sel AND rt.expires_at > NOW()
             LIMIT 1",
            ['sel' => $selector]
        );

        if (!$row || !$row['is_active']) {
            $this->clearRememberToken();
            return false;
        }

        if (!hash_equals($row['hashed_validator'], hash('sha256', $validator))) {
            // Token mismatch – possible theft. Invalidate all tokens for this user.
            $this->db->query(
                "DELETE FROM iw_remember_tokens WHERE user_id = :uid",
                ['uid' => $row['uid']]
            );
            $this->clearRememberToken();
            return false;
        }

        // Valid – rotate the token (single-use)
        $this->db->query(
            "DELETE FROM iw_remember_tokens WHERE id = :id",
            ['id' => $row['id']]
        );

        $this->session->regenerate();
        $this->session->set('user_id', $row['uid']);
        $this->session->set('user_role', $row['role']);
        $this->session->set('user_name', $row['username']);

        // Issue a fresh token so the cookie stays valid
        $this->issueRememberToken((int) $row['uid']);

        return true;
    }

    /**
     * Clear the remember-me cookie and remove the associated DB token.
     */
    private function clearRememberToken(): void
    {
        $cookie = $_COOKIE[self::REMEMBER_COOKIE] ?? '';
        if ($cookie !== '' && str_contains($cookie, ':')) {
            [$selector] = explode(':', $cookie, 2);
            $this->db->query(
                "DELETE FROM iw_remember_tokens WHERE selector = :sel",
                ['sel' => $selector]
            );
        }

        $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
        setcookie(self::REMEMBER_COOKIE, '', [
            'expires'  => time() - 3600,
            'path'     => '/admin',
            'secure'   => $secure,
            'httponly'  => true,
            'samesite' => 'Lax',
        ]);
    }
}