<?php

declare(strict_types=1);

namespace ServerManager\Core;

class View
{
    private string $viewsPath;
    private string $layout = 'main';
    private array $data = [];
    private Security $security;

    public function __construct(Security $security)
    {
        $this->viewsPath = dirname(__DIR__, 2) . '/views/';
        $this->security = $security;
    }

    public function setLayout(string $layout): self
    {
        $this->layout = $layout;
        return $this;
    }

    public function assign(string $key, mixed $value): self
    {
        $this->data[$key] = $value;
        return $this;
    }

    public function assignMultiple(array $data): self
    {
        $this->data = array_merge($this->data, $data);
        return $this;
    }

    public function render(string $view, array $data = []): string
    {
        $data = array_merge($this->data, $data);
        $content = $this->renderView($view, $data);

        if ($this->layout !== null) {
            $data['content'] = $content;
            $content = $this->renderView('layouts/' . $this->layout, $data);
        }

        return $content;
    }

    public function renderView(string $view, array $data = []): string
    {
        $viewFile = $this->viewsPath . str_replace('.', '/', $view) . '.php';

        if (!file_exists($viewFile)) {
            throw new \RuntimeException("View not found: {$view}");
        }

        extract($data, EXTR_SKIP);

        ob_start();
        include $viewFile;
        return ob_get_clean();
    }

    public function renderPartial(string $partial, array $data = []): string
    {
        return $this->renderView('partials/' . $partial, $data);
    }

    public function display(string $view, array $data = []): void
    {
        echo $this->render($view, $data);
    }

    public function escape(string $value): string
    {
        return $this->security->purify($value);
    }

    public function csrfToken(): string
    {
        return $this->security->generateCSRFToken();
    }

    public function csrfField(): string
    {
        $token = $this->csrfToken();
        return '<input type="hidden" name="_csrf_token" value="' . $this->escape($token) . '">';
    }

    public function redirect(string $url, int $statusCode = 302): never
    {
        http_response_code($statusCode);
        header("Location: {$url}");
        exit;
    }

    public function json(mixed $data, int $statusCode = 200): never
    {
        http_response_code($statusCode);
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        exit;
    }

    public function error(int $statusCode, string $message = ''): never
    {
        http_response_code($statusCode);
        if (str_starts_with($_SERVER['HTTP_ACCEPT'] ?? '', 'application/json')) {
            $this->json(['error' => true, 'message' => $message ?: $this->getStatusMessage($statusCode)], $statusCode);
        }
        $this->display("errors.{$statusCode}", [
            'code' => $statusCode,
            'message' => $message ?: $this->getStatusMessage($statusCode),
        ]);
        exit;
    }

    private function getStatusMessage(int $code): string
    {
        return match($code) {
            400 => 'Bad Request',
            401 => 'Unauthorized',
            403 => 'Forbidden',
            404 => 'Not Found',
            405 => 'Method Not Allowed',
            429 => 'Too Many Requests',
            500 => 'Internal Server Error',
            503 => 'Service Unavailable',
            default => 'Error',
        };
    }
}
