<?php

namespace Velis\Mvc\Controller\Utils;

use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\Router\Route;
use Velis\Filter;
use Velis\Mvc\FrontendRouting;
use Velis\Mvc\Router;
use Velis\Output;

class FrontendRouteUrlConverter
{
    public function __construct(
        private readonly Router $router,
        private readonly Filter $filter,
        private readonly Dispatcher $dispatcher,
        private readonly string $referer
    ) {
    }

    public function getRedirectUrl(): ?string
    {
        $routes = $this->router->getRoutes();

        foreach ($routes as $route) {
            $url = $this->getRouteUrl($route);

            if ($url !== null) {
                return $url;
            }
        }

        return null;
    }

    private function getRouteUrl(Route $route): ?string
    {
        if (!$this->isMatchedFrontendRoute($route)) {
            return null;
        }

        $basePattern = $route->getPattern();
        $filterParams = $this->filter->getArrayCopy();
        $hasNamedParams = sizeof($route->extractNamedParams($basePattern)[1]) > 0;

        // if there is a parameter passed in the query string, replace the appropriate placeholder in the route
        $url = $hasNamedParams
            ? preg_replace_callback(
                '/{([\w-]+)}/',
                function ($matches) use ($filterParams) {
                    [$raw, $placeholder] = $matches;
                    $placeholder = strtolower($placeholder);
                    return array_key_exists($placeholder, $filterParams) ? $filterParams[$placeholder] : $raw;
                },
                $basePattern
            )
            : $basePattern;

        // if there are no named params but a filter query is present, append it to the URL
        if (!$hasNamedParams && !empty($filterParams)) {
            $url .= '?' . parse_url($this->referer, PHP_URL_QUERY);
        }

        return $url;
    }

    private function isMatchedFrontendRoute(Route $route): bool
    {
        $routePaths = $route->getPaths();

        $dispatchedModule = Output::toPascalCase($this->dispatcher->getModuleName() ?? '');
        $dispatchedController = Output::toPascalCase($this->dispatcher->getControllerName());
        $dispatchedAction = Output::toPascalCase($this->dispatcher->getActionName());

        $isMatchedFrontendRoute =
            $routePaths['module'] === $dispatchedModule
            && $routePaths['controller'] === $dispatchedController
            && $routePaths['action'] === $dispatchedAction
            && str_starts_with($route->getName(), FrontendRouting::FRONTEND_ROUTE_PREFIX);

        return $isMatchedFrontendRoute;
    }
}
