<?php
declare(strict_types=1);

namespace App\Middleware;

/**
 * Authentication Middleware
 *
 * Handles user authentication and authorization
 */
final class AuthMiddleware
{
    private \PDO $pdo;

    public function __construct(\PDO $pdo)
    {
        $this->pdo = $pdo;
    }

    /**
     * Require user authentication (admin or regular user)
     *
     * @return array<string, mixed> Current user data
     */
    public function requireUser(): array
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        if (!isset($_SESSION['user_id'])) {
            http_response_code(401);
            header('Content-Type: application/json');
            echo json_encode([
                'success' => false,
                'message' => 'Authentication required',
            ], JSON_THROW_ON_ERROR);
            exit;
        }

        return $this->getUserById((int) $_SESSION['user_id']);
    }

    /**
     * Require admin authentication
     *
     * @return array<string, mixed> Current admin user data
     */
    public function requireAdmin(): array
    {
        $user = $this->requireUser();

        if ($user['role'] !== 'admin') {
            http_response_code(403);
            header('Content-Type: application/json');
            echo json_encode([
                'success' => false,
                'message' => 'Admin access required',
            ], JSON_THROW_ON_ERROR);
            exit;
        }

        return $user;
    }

    /**
     * Check if user is authenticated
     *
     * @return bool
     */
    public function isAuthenticated(): bool
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        return isset($_SESSION['user_id']);
    }

    /**
     * Check if user is admin
     *
     * @return bool
     */
    public function isAdmin(): bool
    {
        if (!$this->isAuthenticated()) {
            return false;
        }

        $user = $this->getUserById((int) $_SESSION['user_id']);
        return $user['role'] === 'admin';
    }

    /**
     * Get user by ID
     *
     * @param int $userId
     * @return array<string, mixed>
     */
    private function getUserById(int $userId): array
    {
        $stmt = $this->pdo->prepare(
            'SELECT id, email, full_name, role, status FROM users WHERE id = ? LIMIT 1'
        );
        $stmt->execute([$userId]);
        $user = $stmt->fetch(\PDO::FETCH_ASSOC);

        if (!$user) {
            http_response_code(401);
            header('Content-Type: application/json');
            echo json_encode([
                'success' => false,
                'message' => 'User not found',
            ], JSON_THROW_ON_ERROR);
            exit;
        }

        if ($user['status'] !== 'active') {
            http_response_code(403);
            header('Content-Type: application/json');
            echo json_encode([
                'success' => false,
                'message' => 'Account is not active',
            ], JSON_THROW_ON_ERROR);
            exit;
        }

        return $user;
    }

    /**
     * Login user
     *
     * @param string $email
     * @param string $password
     * @return array{success: bool, message: string, user?: array}
     */
    public function login(string $email, string $password): array
    {
        $stmt = $this->pdo->prepare(
            'SELECT id, email, password_hash, full_name, role, status FROM users WHERE email = ? LIMIT 1'
        );
        $stmt->execute([$email]);
        $user = $stmt->fetch(\PDO::FETCH_ASSOC);

        if (!$user) {
            return ['success' => false, 'message' => 'Invalid credentials'];
        }

        if (!password_verify($password, $user['password_hash'])) {
            return ['success' => false, 'message' => 'Invalid credentials'];
        }

        if ($user['status'] !== 'active') {
            return ['success' => false, 'message' => 'Account is not active'];
        }

        // Start session
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        // Regenerate session ID to prevent fixation
        session_regenerate_id(true);

        // Store user data
        $_SESSION['user_id'] = $user['id'];
        $_SESSION['user_email'] = $user['email'];
        $_SESSION['user_role'] = $user['role'];

        return [
            'success' => true,
            'message' => 'Login successful',
            'user' => [
                'id' => $user['id'],
                'email' => $user['email'],
                'full_name' => $user['full_name'],
                'role' => $user['role'],
            ],
        ];
    }

    /**
     * Logout user
     *
     * @return void
     */
    public function logout(): void
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        $_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();
    }
}
