<?php

namespace AutoAdmin\Bundle\Admin\Router;

use AutoAdmin\Bundle\Admin\Configuration\ConfigManager;
use AutoAdmin\Bundle\Admin\Exception\UnknownEntityException;
use AutoAdmin\Bundle\Admin\Helper\EntityHelper;
use AutoAdmin\Bundle\Content\Translation\EntityTranslator;
use Exception;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\PropertyAccess\PropertyAccessor;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;

final class AdminRouter
{
    private ConfigManager $configManager;
    private UrlGeneratorInterface $urlGenerator;
    private PropertyAccessorInterface $propertyAccessor;
    private EntityTranslator $entityTranslator;
    private EntityHelper $entityHelper;
    private RouterInterface $router;
    private RequestStack $requestStack;

    public function __construct(
        ConfigManager             $configManager,
        UrlGeneratorInterface     $urlGenerator,
        PropertyAccessorInterface $propertyAccessor,
        EntityTranslator          $entityTranslator,
        EntityHelper              $entityHelper,
        RouterInterface           $router,
        RequestStack              $requestStack
    )
    {
        $this->configManager = $configManager;
        $this->urlGenerator = $urlGenerator;
        $this->propertyAccessor = $propertyAccessor;
        $this->entityTranslator = $entityTranslator;
        $this->entityHelper = $entityHelper;
        $this->router = $router;
        $this->requestStack = $requestStack;
    }

    public function generateUrlFromRoute(string $routeName, array $options): string
    {
        return $this->generateWithTranslation($routeName, $options);
    }

    private function generateWithTranslation(string $routeName, array $options): string
    {
        if (empty($options['_admin_locale'])) {
            $options['_admin_locale'] = $this->entityTranslator->getLocale();
        }

        return $this->urlGenerator->generate($routeName, $options);
    }

    /**
     * @throws UnknownEntityException
     */
    public function generate(string|object $entity, string $actionSlug, array $parameters = []): string
    {
        $class = $this->entityHelper->guessFqcn($entity);
        $actionConfig = $this->configManager->getActionConfig($class, $actionSlug);

        if ($actionConfig === null) {
            throw new Exception(
                sprintf('Could not find action configuration for entity "%s" for action "%s"', $class, $actionSlug)
            );
        }
        if (!empty($actionConfig['type']) && $actionConfig['type'] === 'entity_action') {
            $actionConfig['route'] = $actionConfig['target_config']['route'];
            $actionConfig['routeParameters'] = $actionConfig['target_config']['routeParameters'];
            //            dump($actionConfig);
        }

        $routeName = $actionConfig['route'];

        if (
            $routeName === 'aa_admin_entity' &&
            is_object($entity)
            && !is_null($entity->getId())
        ) {
            $parameters['id'] = (string)$this->propertyAccessor->getValue($entity, 'id');
        }

        if (is_object($entity) && !empty($actionConfig['routeParamMap'])) {
            $pa = new PropertyAccessor();
            foreach ($actionConfig['routeParamMap'] ?? [] as $paramKey => $path) {
                if (substr($path, 0, 14) === 'property_path:') {
                    $path = substr($path, 14);
                }
                $parameters[$paramKey] = $pa->getValue($entity, $path);
            }
        }

        $parameters = array_merge($actionConfig['routeParameters'] ?? [], $parameters);
        if (is_null($routeName)) {
            //            dump($entity);
            //            dump($actionConfig);
            //            dump($parameters);
            die;
        }

        $route = $this->router->getRouteCollection()->get($routeName);
        if (!empty($route)) {
            if (strpos($route->getPath(), '{_admin_locale}') !== false) {
                $parameters['_admin_locale'] = $this->requestStack->getCurrentRequest()->get('_admin_locale');
            }
        }

        return $this->router->generate($routeName, $parameters);
    }
}
