<?php

namespace App\Core;

class App
{
    private Router $router;
    private static ?App $instance = null;
    private array $config = [];

    public function __construct()
    {
        self::$instance = $this;
        $this->registerAutoloader();
        $this->router = new Router();
    }

    public static function getInstance(): ?self
    {
        return self::$instance;
    }

    public function getRouter(): Router
    {
        return $this->router;
    }

    public function getConfig(string $key = null)
    {
        if ($key === null) {
            return $this->config;
        }
        return $this->config[$key] ?? null;
    }

    public function init(): self
    {
        $this->loadConfig();
        date_default_timezone_set($this->config['timezone'] ?? 'Europe/Moscow');

        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        $this->setupErrorHandling();
        $this->loadRoutes();

        return $this;
    }

    private function loadConfig(): void
    {
        $configPath = $this->getBasePath() . '/config/app.php';
        if (file_exists($configPath)) {
            $this->config = require $configPath;
        }
    }

    public function getBasePath(): string
    {
        return defined('ROOT_PATH') ? ROOT_PATH : dirname(__DIR__, 2);
    }

    private function registerAutoloader(): void
    {
        spl_autoload_register(function ($class) {
            $prefix = 'App\\';
            $baseDir = dirname(__DIR__) . '/';

            $len = strlen($prefix);
            if (strncmp($prefix, $class, $len) !== 0) {
                return;
            }

            $relativeClass = substr($class, $len);
            $file = $baseDir . str_replace('\\', '/', $relativeClass) . '.php';

            if (file_exists($file)) {
                require $file;
            }
        });
    }

    private function setupErrorHandling(): void
    {
        if ($this->config['debug'] ?? false) {
            error_reporting(E_ALL);
            ini_set('display_errors', '1');
        } else {
            error_reporting(0);
            ini_set('display_errors', '0');
        }

        set_exception_handler(function (\Throwable $e) {
            $this->handleException($e);
        });

        set_error_handler(function ($severity, $message, $file, $line) {
            throw new \ErrorException($message, 0, $severity, $file, $line);
        });
    }

    private function handleException(\Throwable $e): void
    {
        http_response_code(500);

        if ($this->config['debug'] ?? false) {
            echo "<h1>Ошибка приложения</h1>";
            echo "<p><strong>Сообщение:</strong> " . htmlspecialchars($e->getMessage()) . "</p>";
            echo "<p><strong>Файл:</strong> " . htmlspecialchars($e->getFile()) . ":" . $e->getLine() . "</p>";
            echo "<pre>" . htmlspecialchars($e->getTraceAsString()) . "</pre>";
        } else {
            echo View::render('errors/500', [], 'main');
        }
    }

    private function loadRoutes(): void
    {
        $routesFile = $this->getBasePath() . '/config/routes.php';
        
        if (file_exists($routesFile)) {
            $router = $this->router;
            require $routesFile;
        }
    }

    public function run(): void
    {
        $uri = $_SERVER['REQUEST_URI'] ?? '/';
        $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';

        $basePath = $this->config['base_path'] ?? '';
        
        if (!empty($basePath) && strpos($uri, $basePath) === 0) {
            $uri = substr($uri, strlen($basePath));
        }

        if (empty($uri) || $uri === false) {
            $uri = '/';
        }

        try {
            $this->router->dispatch($uri, $method);
        } catch (\Exception $e) {
            $this->handleException($e);
        }
    }
}
