<?php

namespace apexl\Io\utilityIncludes;

use apexl\Config\Exceptions\MissingConfigException;
use apexl\Io\enums\HttpMethod;
use apexl\Io\services\HttpPaths;
use Psr\Http\Server\MiddlewareInterface;

final class Route
{
    /** @var array<int,MiddlewareInterface> */
    private readonly array $middleware;

    /** @var string|array|callable $callable */
    private readonly mixed $callable;

    public function __construct(
        private readonly HttpPaths $httpPaths,
        private readonly string $name,
        private readonly string $pattern,
        string|array|callable $callable,
        private readonly HttpMethod $method,
        private array $args = [],
        array $middleware = []
    ) {
        $this->callable = $callable;
        $this->middleware = $middleware;
    }

    public function getMiddleware(): array
    {
        return $this->middleware;
    }

    public function setArg(string $arg, mixed $value): void
    {
        $this->args[$arg] = $value;
    }

    public function getArgs(): array
    {
        return $this->args;
    }

    public function getName(): string
    {
        return $this->name;
    }

    /**
     * @throws MissingConfigException
     */
    public function getFullyQualifiedPattern(
        array $replacements = [],
        bool $stripTags = true
    ): string {
        return $this->httpPaths->backendUrl($this->getPattern($replacements, $stripTags));
    }

    public function getPattern(
        array $replacements = [],
        bool $stripTags = true
    ): string|false {
        $pattern = $this->pattern;

        foreach ($replacements as $token => $value) {
            $pattern = str_replace(['{' . $token . '}', '[', ']'], [$value, '', ''], $pattern);
        }

        if ($stripTags) {
            return preg_replace('#\[?/\{[^}]+}]?(/|$)#', '$1', $pattern);
        }

        return $pattern;
    }


    public function getCallable(): string|array|callable
    {
        return $this->callable;
    }

    public function getMethod(): HttpMethod
    {
        return $this->method;
    }

    public function getArg(string $arg)
    {
        return $this->args[$arg] ?? null;
    }
}
