<?php

namespace KupShop\ComponentsBundle\DependencyInjection\Compiler;

use KupShop\ComponentsBundle\DependencyInjection\ComponentsExtension;
use KupShop\ComponentsBundle\Twig\ComponentInterface;
use KupShop\ComponentsBundle\Utils\ComponentsLocator;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\UX\Icons\Twig\UXIconComponent;

class ComponentsPass implements CompilerPassInterface
{
    public function __construct(
        protected ComponentsExtension $extension,
    ) {
    }

    public function process(ContainerBuilder $container)
    {
        $factoryDefinition = $container->findDefinition('ux.twig_component.component_factory');
        $componentConfig = $factoryDefinition->getArgument(4);

        $shopConfig = $this->extension->getConfig();
        $shopComponents = $shopConfig['components'];

        $components = [];
        $unusedComponents = [];

        foreach ($componentConfig as $name => &$config) {
            $components[$config['class']] = ['name' => $name, ...$config];

            $config['expose_public_props'] = false;

            if (isset($shopComponents[$name])) {
                $components[$config['class']]['shop'] = $shopComponents[$name];
            } elseif (findModule(\Modules::COMPONENTS, \Modules::SUB_STORYBOOK)) {
                if ($config['class'] != UXIconComponent::class) {
                    $components[$config['class']]['shop']['entrypoint'] = 'base';
                    $components[$config['class']]['shop']['version'] = 1;
                }
            }
        }
        unset($config);

        foreach ($shopComponents as $name => $config) {
            if (!array_key_exists($name, $componentConfig)) {
                throw new \LogicException("Unknown component {$name} defined in components.yaml");
            }
        }

        // Find all Wpj Components
        foreach ($container->findTaggedServiceIds('wpj.component') as $id => $tags) {
            $definition = $container->findDefinition($id);

            $component = &$components[$definition->getClass()];

            foreach ($tags as $tag) {
                $component['latest_version'] = $tag['latestVersion'];
                $component['className'] = strtolower(str_replace(':', '-', $component['name']));

                // If component is not used on shop, remove it from registered components
                if (!isset($component['shop'])) {
                    $unusedComponents[$component['name']] = $component;
                    unset($componentConfig[$component['name']]);
                    continue 2;
                }

                $component['entrypoints'] = $component['shop']['entrypoint'];

                $use_version = $component['shop']['version'];
                $version = $this->findVersion($tag, $use_version, $component['name']);

                $component['template'] = preg_replace('/\.\d+\.html\.twig/', ".{$version['template']}.html.twig", $component['template']);
                $component['shop'] = [...$component['shop'], ...$version];

                $componentConfig[$component['name']]['template'] = $component['template'];

                if (!is_subclass_of($definition->getClass(), ComponentInterface::class)) {
                    throw new \LogicException("Component {$definition->getClass()} must inherit from BaseComponent");
                }

                $definition->addMethodCall('setConfiguration', [$use_version, $component['className']]);
            }
        }

        $factoryDefinition->setArgument(4, $componentConfig);

        // Store components info
        $locator = $container->getDefinition(ComponentsLocator::class);
        $locator->setArgument('$components', $components);
        $locator->setArgument('$unusedComponents', $unusedComponents);

        // HACK
        // override symfony/ux-live-component/src/DependencyInjection/LiveComponentExtension.php
        // use constant instead of container.build_hash parameter for template hashing
        // when shop is redeployed, container.build_hash changes and cached html still reference old hash, which causes RuntimeException
        // The exception: Cannot find a template matching "...". Cache may be corrupt.
        $container->getDefinition('ux.live_component.twig.cache_warmer')->setArgument('$secret', '1234');
    }

    protected function findVersion(array $tag, int $version, string $componentName): ?array
    {
        if ($version > $tag['latestVersion']) {
            throw new \LogicException("Can not find component {$componentName} version {$version}");
        }

        foreach (array_reverse($tag['versions'], true) as $version_from => $config) {
            if ($version_from <= $version) {
                return $config;
            }
        }

        throw new \LogicException('This should never happen!');
    }
}
