<?php
namespace api;

use Domain\Settings\SettingsRepository;

class ApiRouter
{
    private $db;
    private $settingsRepo;

    public function __construct($db, SettingsRepository $settingsRepo)
    {
        $this->db = $db;
        $this->settingsRepo = $settingsRepo;
    }

    public function handle(): void
    {
        if (!headers_sent()) {
            header('Content-Type: application/json; charset=utf-8');
        }

        try {
            if (!$this->authenticate()) {
                self::sendError('UNAUTHORIZED', 'Invalid or missing API key', 401);
                return;
            }

            $endpoint = trim((string)($_GET['endpoint'] ?? ''));
            $action = trim((string)($_GET['action'] ?? ''));

            if ($endpoint === '' || $action === '') {
                self::sendError('BAD_REQUEST', 'Missing endpoint or action parameter', 400);
                return;
            }

            $controller = $this->resolveController($endpoint);
            if ($controller === null) {
                self::sendError('NOT_FOUND', 'Unknown endpoint: ' . $endpoint, 404);
                return;
            }

            if (!method_exists($controller, $action)) {
                self::sendError('NOT_FOUND', 'Unknown action: ' . $action, 404);
                return;
            }

            $controller->$action();
        } catch (\Throwable $e) {
            self::sendError('INTERNAL_ERROR', 'Internal server error', 500);
        }
    }

    private function authenticate(): bool
    {
        $headerKey = isset($_SERVER['HTTP_X_API_KEY']) ? $_SERVER['HTTP_X_API_KEY'] : '';
        if ($headerKey === '') {
            return false;
        }

        $storedKey = $this->settingsRepo->getSingleValue('api_key');
        if ($storedKey === '') {
            return false;
        }

        return hash_equals($storedKey, $headerKey);
    }

    private function resolveController(string $endpoint)
    {
        $factories = $this->getControllerFactories();

        if (!isset($factories[$endpoint])) {
            return null;
        }

        return $factories[$endpoint]();
    }

    private function getControllerFactories(): array
    {
        $db = $this->db;

        return [
            'orders' => function () use ($db) {
                $orderRepo = new \Domain\Order\OrderRepository($db);
                $settingsRepo = new \Domain\Settings\SettingsRepository($db);
                $productRepo = new \Domain\Product\ProductRepository($db);
                $transportRepo = new \Domain\Transport\TransportRepository($db);
                $cronJobRepo = new \Domain\CronJob\CronJobRepository($db);
                $service = new \Domain\Order\OrderAdminService($orderRepo, $productRepo, $settingsRepo, $transportRepo, $cronJobRepo);
                return new Controllers\OrdersApiController($service, $orderRepo);
            },
            'products' => function () use ($db) {
                $productRepo = new \Domain\Product\ProductRepository($db);
                $attrRepo = new \Domain\Attribute\AttributeRepository($db);
                return new Controllers\ProductsApiController($productRepo, $attrRepo);
            },
            'dictionaries' => function () use ($db) {
                $statusRepo = new \Domain\ShopStatus\ShopStatusRepository($db);
                $transportRepo = new \Domain\Transport\TransportRepository($db);
                $paymentRepo = new \Domain\PaymentMethod\PaymentMethodRepository($db);
                $attrRepo = new \Domain\Attribute\AttributeRepository($db);
                $producerRepo = new \Domain\Producer\ProducerRepository($db);
                return new Controllers\DictionariesApiController($statusRepo, $transportRepo, $paymentRepo, $attrRepo, $producerRepo);
            },
        ];
    }

    // =========================================================================
    // Static response helpers
    // =========================================================================

    public static function sendSuccess($data): void
    {
        http_response_code(200);
        echo json_encode(['status' => 'ok', 'data' => $data], JSON_UNESCAPED_UNICODE);
    }

    public static function sendError(string $code, string $message, int $httpCode = 400): void
    {
        http_response_code($httpCode);
        echo json_encode([
            'status' => 'error',
            'code' => $code,
            'message' => $message,
        ], JSON_UNESCAPED_UNICODE);
    }

    public static function getJsonBody(): ?array
    {
        $raw = file_get_contents('php://input');
        if ($raw === '' || $raw === false) {
            return null;
        }

        $data = json_decode($raw, true);

        return is_array($data) ? $data : null;
    }

    public static function requireMethod(string $method): bool
    {
        $requestMethod = isset($_SERVER['REQUEST_METHOD']) ? strtoupper($_SERVER['REQUEST_METHOD']) : 'GET';
        if ($requestMethod !== strtoupper($method)) {
            self::sendError('METHOD_NOT_ALLOWED', 'Method ' . $requestMethod . ' not allowed, expected ' . strtoupper($method), 405);
            return false;
        }

        return true;
    }
}
