<?php

class Auth
{
    public function login($email, $password)
    {
        try {
            if ($this->checkLoginAttempts($email) >= 5) {
                return ['success' => false, 'message' => 'Too many login attempts. Please try again in 15 minutes.'];
            }

            $user = $this->attempt($email, $password);

            if (!$user) {
                $this->incrementLoginAttempts($email);
                return ['success' => false, 'message' => 'Invalid email or password.'];
            }

            if ($user['status'] !== 'active') {
                $this->incrementLoginAttempts($email);
                return ['success' => false, 'message' => 'Your account has been deactivated. Please contact administrator.'];
            }

            $this->resetLoginAttempts($email);

            if (session_status() === PHP_SESSION_ACTIVE && headers_sent() === false) {
                session_regenerate_id(true);
            }
            $_SESSION['user_id'] = (int) $user['id'];
            $_SESSION['user_name'] = $user['name'];
            $_SESSION['user_email'] = $user['email'];
            $_SESSION['user_role'] = $user['role_name'];
            $_SESSION['restaurant_id'] = $user['restaurant_id'] ? (int) $user['restaurant_id'] : null;
            $_SESSION['role_permissions'] = $this->decodePermissions($user['permissions'] ?? '[]');
            $_SESSION['logged_in'] = true;
            $_SESSION['login_time'] = time();

            $this->recordLogin($user['id'], $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1', $_SERVER['HTTP_USER_AGENT'] ?? '');

            try {
                $activityLog = new ActivityLog();
                $activityLog->log(
                    $user['id'],
                    $user['restaurant_id'],
                    'auth',
                    'login',
                    'User logged in successfully',
                    $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1',
                    $_SERVER['HTTP_USER_AGENT'] ?? ''
                );
            } catch (Exception $e) {
                error_log('Activity log failed: ' . $e->getMessage());
            }

            return ['success' => true, 'user' => $user];
        } catch (Exception $e) {
            error_log('Login error for ' . $email . ': ' . $e->getMessage());
            return ['success' => false, 'message' => 'A system error occurred. Please try again later.'];
        }
    }

    public function logout()
    {
        if ($this->check()) {
            try {
                $activityLog = new ActivityLog();
                $activityLog->log(
                    $this->userId(),
                    $this->restaurantId(),
                    'auth',
                    'logout',
                    'User logged out',
                    $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1',
                    $_SERVER['HTTP_USER_AGENT'] ?? ''
                );
            } catch (Exception $e) {
                error_log('Activity log failed: ' . $e->getMessage());
            }
        }

        $_SESSION = [];

        if (ini_get('session.use_cookies')) {
            $params = session_get_cookie_params();
            setcookie(
                session_name(),
                '',
                time() - 42000,
                $params['path'],
                $params['domain'],
                $params['secure'],
                $params['httponly']
            );
        }

        session_destroy();
    }

    public function check()
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }
        return isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true && isset($_SESSION['user_id']);
    }

    public function user()
    {
        if (!$this->check()) {
            return null;
        }
        return [
            'id'       => $_SESSION['user_id'],
            'name'     => $_SESSION['user_name'],
            'email'    => $_SESSION['user_email'],
            'role'     => $_SESSION['user_role'],
            'restaurant_id' => $_SESSION['restaurant_id'],
            'permissions'   => $_SESSION['role_permissions'] ?? [],
        ];
    }

    public function userId()
    {
        return $this->check() ? (int) $_SESSION['user_id'] : null;
    }

    public function userRole()
    {
        return $this->check() ? $_SESSION['user_role'] : null;
    }

    public function restaurantId()
    {
        return $this->check() ? $_SESSION['restaurant_id'] : null;
    }

    public function isSuperAdmin()
    {
        return $this->userRole() === 'super_admin';
    }

    public function isRestaurantAdmin()
    {
        return $this->userRole() === 'restaurant_admin';
    }

    public function hasPermission($module)
    {
        if ($this->isSuperAdmin()) {
            return true;
        }

        $permissions = $_SESSION['role_permissions'] ?? [];

        if (empty($permissions)) {
            return false;
        }

        if (in_array('*', $permissions, true)) {
            return true;
        }

        if (in_array($module, $permissions, true)) {
            return true;
        }

        $parts = explode('.', $module);
        if (count($parts) > 1) {
            $parentModule = $parts[0];
            if (in_array($parentModule . '.*', $permissions, true)) {
                return true;
            }
            foreach ($permissions as $perm) {
                if (is_string($perm) && substr($perm, -2) === '.*') {
                    $permModule = substr($perm, 0, -2);
                    if ($permModule === $parentModule) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    public static function isLoggedIn()
    {
        $auth = new self();
        return $auth->check();
    }

    public function attempt($email, $password)
    {
        try {
            $db = Database::getInstance();
            $sql = "SELECT u.*, r.name AS role_name, COALESCE(r.permissions, '[]') AS permissions
                    FROM users u
                    INNER JOIN roles r ON u.role_id = r.id
                    WHERE u.email = ?
                    LIMIT 1";
            $stmt = $db->query($sql, [$email]);
            $user = $stmt->fetch();

            if ($user && password_verify($password, $user['password'])) {
                unset($user['password']);
                return $user;
            }

            return false;
        } catch (Exception $e) {
            error_log('Auth attempt query failed: ' . $e->getMessage());
            return false;
        }
    }

    public function requireLogin()
    {
        if (!$this->check()) {
            redirect('/login.php');
        }
    }

    public function requireRole($roles)
    {
        $this->requireLogin();

        if (!is_array($roles)) {
            $roles = [$roles];
        }

        if (!in_array($this->userRole(), $roles)) {
            redirect('/login.php');
        }
    }

    public function requireRestaurantAccess($restaurantId)
    {
        $this->requireLogin();

        if ($this->isSuperAdmin()) {
            return true;
        }

        if ($this->restaurantId() != $restaurantId) {
            redirect('/login.php');
        }

        return true;
    }

    public function regenerateSession()
    {
        if ($this->check()) {
            session_regenerate_id(true);
        }
    }

    public function recordLogin($userId, $ip, $userAgent)
    {
        try {
            $db = Database::getInstance();
            $db->update(
                'users',
                [
                    'last_login'     => date('Y-m-d H:i:s'),
                    'last_login_ip'  => $ip,
                    'last_login_ua'  => $userAgent,
                ],
                'id = ?',
                [$userId]
            );
        } catch (Exception $e) {
            error_log('Record login failed: ' . $e->getMessage());
        }
    }

    public function checkLoginAttempts($email)
    {
        try {
            $db = Database::getInstance();
            $stmt = $db->query(
                "SELECT COUNT(*) AS attempts FROM login_attempts WHERE email = ? AND attempted_at > DATE_SUB(NOW(), INTERVAL 15 MINUTE)",
                [$email]
            );
            $result = $stmt->fetch();
            return (int) ($result['attempts'] ?? 0);
        } catch (Exception $e) {
            error_log('Check login attempts failed: ' . $e->getMessage());
            return 0;
        }
    }

    public function incrementLoginAttempts($email)
    {
        try {
            $db = Database::getInstance();
            $ip = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
            $db->insert('login_attempts', [
                'email'        => $email,
                'ip_address'   => $ip,
                'attempted_at' => date('Y-m-d H:i:s'),
            ]);
        } catch (Exception $e) {
            error_log('Increment login attempts failed: ' . $e->getMessage());
        }
    }

    public function resetLoginAttempts($email)
    {
        try {
            $db = Database::getInstance();
            $db->delete('login_attempts', 'email = ?', [$email]);
        } catch (Exception $e) {
            error_log('Reset login attempts failed: ' . $e->getMessage());
        }
    }

    private function decodePermissions($permissionsJson)
    {
        if (empty($permissionsJson) || $permissionsJson === 'null') {
            return [];
        }

        if (!is_string($permissionsJson)) {
            if (is_array($permissionsJson)) {
                return $permissionsJson;
            }
            return [];
        }

        $decoded = json_decode($permissionsJson, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            $decoded = array_map('trim', explode(',', $permissionsJson));
            $decoded = array_filter($decoded);
            return array_values($decoded);
        }

        if (!is_array($decoded)) {
            return [];
        }

        return array_values($decoded);
    }
}
