<?php
// ========================================
// سیستم احراز هویت - نسخه امن‌شده
// پروژه فروشگاه کیف‌لند
// ========================================

require_once __DIR__ . '/../config/database.php';

if (session_status() === PHP_SESSION_NONE) {
    session_set_cookie_params([
        'lifetime' => 0,
        'path'     => '/',
        'secure'   => isset($_SERVER['HTTPS']),
        'httponly' => true,
        'samesite' => 'Lax',
    ]);
    session_start();
}

class Auth {

    // ========================================
    // Session Timeout (30 دقیقه)
    // ========================================
    private static int $SESSION_TIMEOUT = 1800;

    public static function checkSessionTimeout(): void {
        if (!self::isLoggedIn()) return;
        $last = $_SESSION['last_activity'] ?? 0;
        if ($last && (time() - $last) > self::$SESSION_TIMEOUT) {
            self::forceLogout();
            return;
        }
        $_SESSION['last_activity'] = time();
    }

    private static function forceLogout(): void {
        session_unset();
        session_destroy();
        if (!headers_sent()) {
            header('Location: /login.php?timeout=1');
        } else {
            echo "<script>window.location.href='/login.php?timeout=1';</script>";
        }
        exit;
    }

    // ========================================
    // Rate Limiting برای ورود
    // ========================================
    private static int $MAX_ATTEMPTS = 5;
    private static int $LOCKOUT_TIME = 900; // 15 دقیقه

    public static function isRateLimited(string $ip): bool {
        $key  = 'login_fail_' . md5($ip);
        $data = $_SESSION[$key] ?? ['count' => 0, 'first' => 0];

        if ($data['count'] >= self::$MAX_ATTEMPTS) {
            if ((time() - $data['first']) < self::$LOCKOUT_TIME) {
                return true;
            }
            // بعد از گذشت timeout ریست کن
            unset($_SESSION[$key]);
        }
        return false;
    }

    public static function recordFailedLogin(string $ip): void {
        $key  = 'login_fail_' . md5($ip);
        $data = $_SESSION[$key] ?? ['count' => 0, 'first' => time()];
        $data['count']++;
        if ($data['count'] === 1) $data['first'] = time();
        $_SESSION[$key] = $data;
    }

    public static function resetLoginAttempts(string $ip): void {
        unset($_SESSION['login_fail_' . md5($ip)]);
    }

    public static function getRemainingLockout(string $ip): int {
        $key  = 'login_fail_' . md5($ip);
        $data = $_SESSION[$key] ?? null;
        if (!$data || $data['count'] < self::$MAX_ATTEMPTS) return 0;
        $remaining = self::$LOCKOUT_TIME - (time() - $data['first']);
        return max(0, (int)ceil($remaining / 60));
    }

    // ========================================
    // بررسی ورود کاربر
    // ========================================
    public static function isLoggedIn(): bool {
        return isset($_SESSION['user_id']);
    }

    public static function isAdmin(): bool {
        return isset($_SESSION['role']) && $_SESSION['role'] === 'admin';
    }

    public static function currentUser(): ?array {
        if (!self::isLoggedIn()) return null;
        try {
            $db   = Database::getInstance()->getConnection();
            $stmt = $db->prepare("SELECT id, username, email, full_name, avatar, role, phone, created_at, last_login FROM users WHERE id = ? AND is_active = 1");
            $stmt->execute([$_SESSION['user_id']]);
            return $stmt->fetch() ?: null;
        } catch (Exception $e) {
            error_log("Current User Error: " . $e->getMessage());
            return null;
        }
    }

    // ========================================
    // ورود کاربر
    // ========================================
    public static function login(string $email, string $password, bool $remember = false): bool|string {
        $ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';

        if (self::isRateLimited($ip)) {
            return 'rate_limited';
        }

        try {
            $db   = Database::getInstance()->getConnection();
            $stmt = $db->prepare("SELECT * FROM users WHERE email = ?");
            $stmt->execute([$email]);
            $user = $stmt->fetch();

            if ($user && password_verify($password, $user['password'])) {
                if (!$user['is_active']) return 'inactive';

                self::resetLoginAttempts($ip);

                // بازسازی session برای جلوگیری از session fixation
                session_regenerate_id(true);

                $_SESSION['user_id']       = $user['id'];
                $_SESSION['role']          = $user['role'];
                $_SESSION['username']      = $user['username'];
                $_SESSION['email']         = $user['email'];
                $_SESSION['full_name']     = $user['full_name'];
                $_SESSION['last_activity'] = time();

                $db->prepare("UPDATE users SET last_login = NOW() WHERE id = ?")->execute([$user['id']]);
                self::logActivity('login', 'ورود به حساب کاربری');

                if ($remember) {
                    $token = bin2hex(random_bytes(32));
                    setcookie('remember_token', $token, time() + (30 * 24 * 60 * 60), '/', '', isset($_SERVER['HTTPS']), true);
                    $db->prepare("UPDATE users SET remember_token = ? WHERE id = ?")->execute([$token, $user['id']]);
                }

                return true;
            }

            self::recordFailedLogin($ip);
            return false;

        } catch (Exception $e) {
            error_log("Login Error: " . $e->getMessage());
            return false;
        }
    }

    // ========================================
    // ثبت‌نام کاربر جدید
    // ========================================
    public static function register(string $username, string $email, string $password, string $fullName, string $phone = ''): bool {
        try {
            $db    = Database::getInstance()->getConnection();
            $check = $db->prepare("SELECT id FROM users WHERE email = ? OR username = ?");
            $check->execute([$email, $username]);
            if ($check->fetch()) return false;

            $hashed = password_hash($password, PASSWORD_DEFAULT);
            $stmt   = $db->prepare("INSERT INTO users (username, email, password, full_name, phone, role, created_at) VALUES (?, ?, ?, ?, ?, 'user', NOW())");
            $result = $stmt->execute([$username, $email, $hashed, $fullName, $phone]);

            if ($result) {
                self::logActivity('register', 'ثبت‌نام کاربر جدید: ' . $username, $db->lastInsertId());
            }
            return $result;
        } catch (Exception $e) {
            error_log("Register Error: " . $e->getMessage());
            return false;
        }
    }

    // ========================================
    // خروج
    // ========================================
    public static function logout(): void {
        if (self::isLoggedIn()) {
            self::logActivity('logout', 'خروج از حساب کاربری');
        }

        if (isset($_COOKIE['remember_token'])) {
            try {
                $db = Database::getInstance()->getConnection();
                $db->prepare("UPDATE users SET remember_token = NULL WHERE id = ?")->execute([$_SESSION['user_id']]);
            } catch (Exception $e) {}
            setcookie('remember_token', '', time() - 3600, '/');
        }

        session_unset();
        session_destroy();

        if (headers_sent()) {
            echo "<script>window.location.href='index.php';</script>";
        } else {
            header('Location: index.php');
        }
        exit;
    }

    // ========================================
    // Rate Limiting فرم‌های عمومی (پیام، ثبت‌نام)
    // ========================================
    public static function isFormRateLimited(string $formKey, int $maxPerHour = 10): bool {
        $key  = 'form_' . $formKey . '_' . md5($_SERVER['REMOTE_ADDR'] ?? '');
        $data = $_SESSION[$key] ?? ['count' => 0, 'window' => time()];

        if ((time() - $data['window']) > 3600) {
            $data = ['count' => 0, 'window' => time()];
        }
        if ($data['count'] >= $maxPerHour) return true;

        $data['count']++;
        $_SESSION[$key] = $data;
        return false;
    }

    // ========================================
    // CSRF Token
    // ========================================
    public static function generateCSRFToken(): string {
        if (empty($_SESSION['csrf_token'])) {
            $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        }
        return $_SESSION['csrf_token'];
    }

    public static function verifyCSRFToken(string $token): bool {
        return !empty($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
    }

    // ========================================
    // اعتبارسنجی فایل آپلود (امن)
    // ========================================
    public static function validateImageUpload(array $file): array {
        $result = ['ok' => false, 'error' => ''];

        if ($file['error'] !== UPLOAD_ERR_OK) {
            $result['error'] = 'خطا در آپلود فایل.';
            return $result;
        }

        $maxSize = 3 * 1024 * 1024;
        if ($file['size'] > $maxSize) {
            $result['error'] = 'حجم فایل نباید بیشتر از ۳ مگابایت باشد.';
            return $result;
        }

        // بررسی واقعی محتوای فایل (نه فقط mime_type ارسالی)
        $finfo    = new finfo(FILEINFO_MIME_TYPE);
        $realMime = $finfo->file($file['tmp_name']);
        $allowed  = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];

        if (!in_array($realMime, $allowed, true)) {
            $result['error'] = 'فقط فرمت‌های JPG، PNG، GIF و WEBP مجاز است.';
            return $result;
        }

        // تأیید اینکه واقعاً تصویر است
        if (!@getimagesize($file['tmp_name'])) {
            $result['error'] = 'فایل انتخابی یک تصویر معتبر نیست.';
            return $result;
        }

        $result['ok']   = true;
        $result['mime'] = $realMime;
        return $result;
    }

    // ========================================
    // متدهای قبلی (بدون تغییر)
    // ========================================
    public static function trackVisit(string $page): void {
        try {
            $db        = Database::getInstance()->getConnection();
            $ip        = $_SERVER['REMOTE_ADDR'];
            $userAgent = $_SERVER['HTTP_USER_AGENT'];
            $userId    = self::isLoggedIn() ? $_SESSION['user_id'] : null;
            $sessionId = session_id();
            $stmt = $db->prepare("INSERT INTO page_views (page_name, ip_address, user_agent, user_id, session_id, visited_at) VALUES (?, ?, ?, ?, ?, NOW())");
            $stmt->execute([$page, $ip, $userAgent, $userId, $sessionId]);
        } catch (Exception $e) {}
    }

    public static function requireLogin(): void {
        if (!self::isLoggedIn()) {
            $_SESSION['redirect_after_login'] = $_SERVER['REQUEST_URI'];
            headers_sent() ? print("<script>window.location.href='login.php';</script>") : header('Location: login.php');
            exit;
        }
    }

    public static function requireAdmin(): void {
        if (!self::isAdmin()) {
            headers_sent() ? print("<script>window.location.href='../index.php';</script>") : header('Location: ../index.php');
            exit;
        }
    }

    public static function updateUserPassword(int $userId, string $newPassword): bool {
        try {
            $db = Database::getInstance()->getConnection();
            return $db->prepare("UPDATE users SET password = ?, updated_at = NOW() WHERE id = ?")->execute([password_hash($newPassword, PASSWORD_DEFAULT), $userId]);
        } catch (Exception $e) { error_log("Password Update Error: " . $e->getMessage()); return false; }
    }

    public static function updateUserProfile(int $userId, array $data): bool {
        try {
            $db = Database::getInstance()->getConnection();
            return $db->prepare("UPDATE users SET full_name = ?, phone = ?, email = ?, updated_at = NOW() WHERE id = ?")->execute([$data['full_name'], $data['phone'], $data['email'], $userId]);
        } catch (Exception $e) { error_log("Profile Update Error: " . $e->getMessage()); return false; }
    }

    public static function updateUserRole(int $userId, string $role): bool {
        try {
            $db = Database::getInstance()->getConnection();
            return $db->prepare("UPDATE users SET role = ?, updated_at = NOW() WHERE id = ?")->execute([$role, $userId]);
        } catch (Exception $e) { return false; }
    }

    public static function toggleUserStatus(int $userId): bool {
        try {
            $db = Database::getInstance()->getConnection();
            return $db->prepare("UPDATE users SET is_active = NOT is_active, updated_at = NOW() WHERE id = ?")->execute([$userId]);
        } catch (Exception $e) { return false; }
    }

    public static function deleteUser(int $userId): bool {
        try {
            $db = Database::getInstance()->getConnection();
            return $db->prepare("DELETE FROM users WHERE id = ?")->execute([$userId]);
        } catch (Exception $e) { return false; }
    }

    public static function logActivity(string $action, string $description = '', ?int $userId = null): bool {
        try {
            $db        = Database::getInstance()->getConnection();
            $ip        = $_SERVER['REMOTE_ADDR'];
            $userAgent = $_SERVER['HTTP_USER_AGENT'];
            $logUserId = $userId ?? (self::isLoggedIn() ? $_SESSION['user_id'] : null);
            return $db->prepare("INSERT INTO activity_logs (user_id, action, description, ip_address, user_agent, created_at) VALUES (?, ?, ?, ?, ?, NOW())")->execute([$logUserId, $action, $description, $ip, $userAgent]);
        } catch (Exception $e) { return false; }
    }

    public static function checkRememberToken(): bool {
        if (isset($_COOKIE['remember_token']) && !self::isLoggedIn()) {
            try {
                $db   = Database::getInstance()->getConnection();
                $stmt = $db->prepare("SELECT * FROM users WHERE remember_token = ? AND is_active = 1");
                $stmt->execute([$_COOKIE['remember_token']]);
                $user = $stmt->fetch();
                if ($user) {
                    session_regenerate_id(true);
                    $_SESSION['user_id']       = $user['id'];
                    $_SESSION['role']          = $user['role'];
                    $_SESSION['username']      = $user['username'];
                    $_SESSION['last_activity'] = time();
                    return true;
                }
            } catch (Exception $e) {}
        }
        return false;
    }

    public static function validateEmail(string $email): bool {
        return (bool) filter_var($email, FILTER_VALIDATE_EMAIL);
    }

    public static function validatePhone(string $phone): bool {
        return (bool) preg_match('/^09[0-9]{9}$/', str_replace('-', '', $phone));
    }

    public static function validatePassword(string $password): bool {
        return strlen($password) >= 8;
    }
}
