<?php
namespace Core;

/**
 * Base Controller
 */
abstract class Controller
{
    protected Database $db;

    public function __construct()
    {
        $this->db = Database::getInstance();
    }

    protected function adminView(string $view, array $data = []): void
    {
        $this->view($view, $data, 'admin');
    }

    protected function view(string $view, array $data = [], string $layout = 'main'): void
    {
        extract($data);
        $viewFile = VIEWS_PATH . '/' . str_replace('.', '/', $view) . '.php';
        if (!file_exists($viewFile)) {
            die("View not found: {$view}");
        }
        ob_start();
        include $viewFile;
        $content = ob_get_clean();

        if ($layout) {
            $layoutFile = VIEWS_PATH . '/layouts/' . $layout . '.php';
            if (file_exists($layoutFile)) {
                include $layoutFile;
                return;
            }
        }
        echo $content;
    }

    protected function json(mixed $data, int $status = 200): void
    {
        http_response_code($status);
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
        exit;
    }

    protected function redirect(string $url): void
    {
        header("Location: {$url}");
        exit;
    }

    protected function back(): void
    {
        $this->redirect($_SERVER['HTTP_REFERER'] ?? APP_URL);
    }

    protected function isPost(): bool
    {
        return $_SERVER['REQUEST_METHOD'] === 'POST';
    }

    protected function isAjax(): bool
    {
        return isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
               strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
    }

    protected function input(string $key, mixed $default = null): mixed
    {
        return $_POST[$key] ?? $_GET[$key] ?? $default;
    }

    protected function file(string $key): array|null
    {
        return $_FILES[$key] ?? null;
    }

    protected function abort(int $code): void
    {
        http_response_code($code);
        $file = VIEWS_PATH . "/errors/{$code}.php";
        if (file_exists($file)) include $file;
        exit;
    }

    protected function requireAuth(): void
    {
        if (!isset($_SESSION['user_id'])) {
            $this->redirect(APP_URL . '/login');
        }
    }

    protected function requireRole(array|string $roles): void
    {
        $this->requireAuth();
        $userRole = $_SESSION['user_role'] ?? '';
        $roles = (array) $roles;
        if (!in_array($userRole, $roles)) {
            $this->abort(403);
        }
    }

    protected function csrfToken(): string
    {
        if (empty($_SESSION[CSRF_TOKEN_NAME])) {
            $_SESSION[CSRF_TOKEN_NAME] = bin2hex(random_bytes(32));
        }
        return $_SESSION[CSRF_TOKEN_NAME];
    }

    protected function verifyCsrf(): void
    {
        $token = $_POST[CSRF_TOKEN_NAME] ?? '';
        if (!hash_equals($_SESSION[CSRF_TOKEN_NAME] ?? '', $token)) {
            $this->abort(419);
        }
    }

    protected function paginate(int $total, int $perPage = ITEMS_PER_PAGE): array
    {
        $page = max(1, (int) ($_GET['page'] ?? 1));
        $totalPages = (int) ceil($total / $perPage);
        $offset = ($page - 1) * $perPage;
        return [
            'page'        => $page,
            'perPage'     => $perPage,
            'total'       => $total,
            'totalPages'  => $totalPages,
            'offset'      => $offset,
            'hasPrev'     => $page > 1,
            'hasNext'     => $page < $totalPages,
        ];
    }
}
