<?php

namespace KupShop\ContentBundle\Util;

use KupShop\ComponentsBundle\Utils\ComponentsLocator;
use KupShop\KupShopBundle\Config;
use KupShop\KupShopBundle\Context\DomainContext;
use KupShop\KupShopBundle\Context\LanguageContext;
use KupShop\KupShopBundle\Util\Logging\SentryLogger;
use KupShop\LLMBundle\TextObjects\BlocekTextBlock;
use KupShop\LLMBundle\TextObjects\ProductBlocekTextBlock;
use KupShop\LLMBundle\Util\TextObjectUtil;
use Symfony\Contracts\Service\Attribute\Required;

class BlocekSettings
{
    #[Required]
    public DomainContext $domainContext;
    #[Required]
    public LanguageContext $languageContext;

    public ?ComponentsLocator $componentsLocator;

    public ?TextObjectUtil $textObjectUtil;

    #[Required]
    public SentryLogger $sentryLogger;

    private bool $isDevelopment;
    private bool $isWpjAdmin;
    private bool $allowHtml;
    private string $urlPrefix;
    private string $adminPath;
    private string $language;
    private string $feLanguage;
    private array $modules;
    private array $components;
    private array $llmPrompts;

    public function fetchSettings(): void
    {
        $config = Config::get()->getContainer();
        $settings = \Settings::getDefault();
        $user = getAdminUser();

        $isLocalDev = ($this->domainContext->getActiveId() == 'www.kupshop.local' || $this->domainContext->getActiveId() == 'kupshop.local');
        $originalAddr = $config['Addr']['full_original'] ?? '/';
        $adminPath = $config['Path']['admin'];

        $this->isDevelopment = (isDevelopment() && $isLocalDev);
        $this->urlPrefix = "{$originalAddr}{$adminPath}";
        $this->adminPath = '/'.ltrim($adminPath, '/');
        $this->isWpjAdmin = $user['superuser'] ?? false;
        $this->allowHtml = $settings['blocek_allow_html'] == 'Y';
        $this->language = $config['Lang']['language'] == 'en' ? 'en' : 'cs';
        $this->feLanguage = $this->languageContext->getActiveId();
        $this->modules = $this->loadModules();

        if (findModule(\Modules::COMPONENTS)) {
            $this->components = $this->loadComponents();
        }

        if (findModule(\Modules::LLM)) {
            $this->llmPrompts = $this->loadLlmPrompts([BlocekTextBlock::getLabel(), ProductBlocekTextBlock::getLabel()]);
        }
    }

    private function loadModules(): array
    {
        return [
            \Modules::COMPONENTS => findModule(\Modules::COMPONENTS),
            \Modules::VIDEOS => findModule(\Modules::CDN) && findModule(\Modules::VIDEOS),
        ];
    }

    private function loadComponents(): array
    {
        $loadedComponents = [];
        try {
            foreach ($this->componentsLocator->getComponents() as $component) {
                $reflectionClass = new \ReflectionClass($component['class']);
                if ($attributes = $reflectionClass->getAttributes('KupShop\ComponentsBundle\Attributes\Blocek', \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null) {
                    $loadedComponents[] = [
                        'name' => $component['name'],
                        'title' => $attributes->getArguments()['title'] ?? null,
                        'descr' => $attributes->getArguments()['descr'] ?? null,
                        'icon' => $attributes->getArguments()['icon'] ?? null,
                        'attributes' => $this->loadAttributes($reflectionClass),
                        'lazy_component' => $attributes->getArguments()['lazy'] ?? false,
                    ];
                }
            }
        } catch (\ReflectionException $e) {
            $this->sentryLogger->captureException($e);
        }

        return $loadedComponents;
    }

    private function loadLlmPrompts(array $textObjects): array
    {
        $result = [];
        foreach ($textObjects as $textObject) {
            $result[$textObject] = array_values(array_map(fn ($prompt) => [
                'id' => $prompt->getId(),
                'title' => $prompt->getTitle(),
            ], $this->textObjectUtil->getObjectLabelPrompts($textObject)));
        }

        return $result;
    }

    /** @throws \Exception */
    private function loadAttributes(\ReflectionClass $reflectionClass): array
    {
        $loadedAttributes = [];
        foreach ($reflectionClass->getProperties() as $property) {
            if ($attributes = $property->getAttributes('KupShop\ComponentsBundle\Attributes\BlocekAttribute', \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null) {
                $loadedAttributes[$property->getName()] = [
                    'name' => $property->getName(),
                    'default' => !empty($attributes->getArguments()['default']) ? $attributes->getArguments()['default'] : $property->getDefaultValue(),
                    'type' => !empty($attributes->getArguments()['type']) ? $attributes->getArguments()['type'] : $this->processBlocekTypeConversion($property),
                    'title' => !empty($attributes->getArguments()['title']) ? $attributes->getArguments()['title'] : $property->getName(),
                    'options' => $this->getAttributeOptionValues($attributes, $reflectionClass),
                ];
                if (!empty($attributes->getArguments()['autocompleteType'])) {
                    $loadedAttributes[$property->getName()]['autocompleteType'] = $attributes->getArguments()['autocompleteType'];
                    $loadedAttributes[$property->getName()]['autocompleteMulti'] = !empty($attributes->getArguments()['autocompleteMulti']) ? $attributes->getArguments()['autocompleteMulti'] : false;
                    $loadedAttributes[$property->getName()]['autocompletePreload'] = !empty($attributes->getArguments()['autocompletePreload']) ? $attributes->getArguments()['autocompletePreload'] : null;
                    $loadedAttributes[$property->getName()]['autocompleteInvert'] = isset($attributes->getArguments()['autocompleteInvert']) ? $attributes->getArguments()['autocompleteInvert'] : null;
                    $loadedAttributes[$property->getName()]['autocompleteSortable'] = isset($attributes->getArguments()['autocompleteSortable']) ? $attributes->getArguments()['autocompleteSortable'] : null;
                }
            }
        }

        return $loadedAttributes;
    }

    private function getAttributeOptionValues(\ReflectionAttribute $attributes, \ReflectionClass $class): array
    {
        if (!empty($attributes->getArguments()['options'])) {
            $options = $attributes->getArguments()['options'];
            if (is_string($options) && $class->hasMethod($options)) {
                return $class->getMethod($options)->invoke(null);
            }

            return $attributes->getArguments()['options'];
        }

        return [];
    }

    private function processBlocekTypeConversion(\ReflectionProperty $property): BlocekTypes
    {
        return match ($property->getType()->getName()) {
            'int' => BlocekTypes::NUMBER,
            'string' => BlocekTypes::TEXT,
            'bool' => BlocekTypes::TOGGLE,
            default => throw new \Exception('Add new conversion type or specify trough parameter'),
        };
    }

    public function isDevelopment(): bool
    {
        return $this->isDevelopment;
    }

    public function getUrlPrefix(): string
    {
        return $this->urlPrefix;
    }

    public function isWpjAdmin(): bool
    {
        return $this->isWpjAdmin;
    }

    public function isAllowHtml(): bool
    {
        return $this->allowHtml;
    }

    public function getLanguage(): string
    {
        return $this->language;
    }

    public function getFeLanguage(): string
    {
        return $this->feLanguage;
    }

    public function getModules(): array
    {
        return $this->modules;
    }

    public function getComponents(): array
    {
        return $this->components;
    }

    public function asArray(): array
    {
        $array = [
            'isDevelopment' => $this->isDevelopment,
            'isWpjAdmin' => $this->isWpjAdmin,
            'allowHtml' => $this->allowHtml,
            'urlPrefix' => $this->urlPrefix,
            'adminPath' => $this->adminPath,
            'language' => $this->language,
            'feLanguage' => $this->feLanguage,
            'modules' => $this->modules,
            'llmPrompts' => $this->llmPrompts,
        ];

        if (findModule(\Modules::COMPONENTS)) {
            $array['components'] = $this->components;
        }

        return $array;
    }

    #[Required]
    public function setComponentsLocator(?ComponentsLocator $componentsLocator = null): void
    {
        $this->componentsLocator = $componentsLocator;
    }

    #[Required]
    public function setTextObjectUtil(?TextObjectUtil $textObjectUtil): void
    {
        $this->textObjectUtil = $textObjectUtil;
    }
}
