<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\PageBuilder\Routing;

use CpCreation\VitiCore\PageBuilder\Model\Page;
use CpCreation\VitiCore\PageBuilder\Model\Translation\PageTranslation;
use CpCreation\VitiCore\PageBuilder\Repository\PageRepository;
use Symfony\Component\HttpFoundation\Request;

final readonly class PageBuilderEntryResolver
{
    public function __construct(
        private PageRepository $pageRepository,
        private RouteTemplatePageImporter $routeTemplatePageImporter,
    ) {
    }

    public function findCmsPageForRequest(Request $request): ?Page
    {
        $path = trim((string) $request->attributes->get('path', ''), '/');

        return $this->pageRepository->findOneCmsByPathForAdmin($path, $request->getLocale());
    }

    public function findOrCreateSystemPageForRequest(Request $request): Page
    {
        $routeName = trim((string) $request->attributes->get('_route'));
        if ('' === $routeName) {
            throw new \InvalidArgumentException('Impossible de créer une page builder sans route Symfony.');
        }

        $pageCode = $this->systemPageCode($routeName);
        $page = $this->pageRepository->findOneSystemByRouteName($routeName)
            ?? $this->pageRepository->findOneByCode($pageCode);
        if ($page instanceof Page) {
            if (!$this->hasBuilderDocumentForLocale($page, $request->getLocale())) {
                $this->routeTemplatePageImporter->import($page, $request->getLocale());
                $this->pageRepository->save($page);
            }

            return $page;
        }

        $page = new Page($pageCode, $this->systemPageName($routeName));
        $page->setSystem(true);
        $page->setRouteName($routeName);
        $page->setTemplate(Page::TEMPLATE_DEFAULT);
        $page->setSetting('sourceRoute', $routeName);
        $page->setSetting('sourcePath', $request->getPathInfo());

        $routeParameters = $this->routeParameters($request);
        if ([] !== $routeParameters) {
            $page->setSetting('sourceRouteParameters', $routeParameters);
        }

        /** @var PageTranslation $translation */
        $translation = $page->translate($request->getLocale(), true);
        $translation->setTitle($page->getName());
        $translation->setPath('');

        $this->routeTemplatePageImporter->import($page, $request->getLocale());
        $this->pageRepository->save($page);

        return $page;
    }

    private function systemPageCode(string $routeName): string
    {
        $normalized = strtolower((string) preg_replace('/[^a-z0-9]+/i', '_', $routeName));
        $normalized = trim($normalized, '_');
        $normalized = '' !== $normalized ? $normalized : 'system_page';

        $code = 'system__'.$normalized;
        if (\strlen($code) <= 64) {
            return $code;
        }

        return substr($code, 0, 55).'_'.substr(md5($routeName), 0, 8);
    }

    private function systemPageName(string $routeName): string
    {
        $label = str_replace(['_', '-'], ' ', trim($routeName));
        $label = ucwords($label);

        return '' !== $label ? $label : 'Page système';
    }

    private function hasBuilderDocumentForLocale(Page $page, string $locale): bool
    {
        $documents = $page->getSetting('builderDocumentByLocale', []);
        if (!\is_array($documents)) {
            return false;
        }

        return \is_array($documents[$locale] ?? null) && [] !== $documents[$locale];
    }

    /**
     * @return array<string, scalar>
     */
    private function routeParameters(Request $request): array
    {
        $parameters = [];
        foreach ($request->attributes->all() as $key => $value) {
            if (str_starts_with((string) $key, '_')) {
                continue;
            }

            if (\is_scalar($value)) {
                $parameters[(string) $key] = $value;
            }
        }

        return $parameters;
    }
}
