<?php
declare(strict_types=1);

namespace Ekesto\CacheInvalidator\Integrations\Multilingual;

/**
 * Helper utilities for multilingual resolver metadata and language context.
 */
final class ResolverContext
{
    /**
     * Build multilingual context payload for emission metadata.
     *
     * @param LanguageResolverInterface|null $resolver Active resolver.
     * @param string|null $triggerLanguage Trigger language code.
     * @param array<string,mixed> $additionalContext Additional resolver context.
     * @return array<string,mixed>
     */
    public static function buildContext(
        ?LanguageResolverInterface $resolver,
        ?string $triggerLanguage,
        array $additionalContext = []
    ): array {
        if ($resolver === null || !is_string($triggerLanguage) || trim($triggerLanguage) === '') {
            return [];
        }

        $languages = self::resolveTargetLanguages(
            $resolver,
            $triggerLanguage,
            $additionalContext
        );

        if (empty($languages)) {
            $languages = [$triggerLanguage];
        }

        return [
            'multilingual' => true,
            'language' => $triggerLanguage,
            'languages' => $languages,
            'resolver' => self::getResolverKey($resolver),
            'resolver_model' => self::getResolverModel($resolver),
        ];
    }

    /**
     * Resolve normalized target languages for a trigger language.
     *
     * @param LanguageResolverInterface $resolver Active resolver.
     * @param string $triggerLanguage Trigger language code.
     * @param array<string,mixed> $additionalContext Additional resolver context.
     * @return string[]
     */
    public static function resolveTargetLanguages(
        LanguageResolverInterface $resolver,
        string $triggerLanguage,
        array $additionalContext = []
    ): array {
        $context = array_merge(
            [
                'trigger_language' => $triggerLanguage,
            ],
            $additionalContext
        );

        $languages = $resolver->resolveTargetLanguages($context);

        return self::normalizeLanguages(is_array($languages) ? $languages : []);
    }

    /**
     * Returns the resolver key for context metadata.
     *
     * @param LanguageResolverInterface $resolver Active resolver.
     * @return string
     */
    public static function getResolverKey(LanguageResolverInterface $resolver): string
    {
        if ($resolver instanceof ResolverMetadataInterface) {
            $key = sanitize_key($resolver->getResolverKey());
            if ($key !== '') {
                return $key;
            }
        }

        $classBase = sanitize_key((string) preg_replace('/LanguageResolver$/', '', self::classBasename($resolver)));
        return $classBase !== '' ? $classBase : 'custom';
    }

    /**
     * Returns the resolver model for context metadata.
     *
     * @param LanguageResolverInterface $resolver Active resolver.
     * @return string
     */
    public static function getResolverModel(LanguageResolverInterface $resolver): string
    {
        if ($resolver instanceof ResolverMetadataInterface) {
            $model = (string) $resolver->getTranslationModel();
            if (in_array($model, [ResolverMetadataInterface::MODEL_OBJECT, ResolverMetadataInterface::MODEL_URL], true)) {
                return $model;
            }
        }

        return ResolverMetadataInterface::MODEL_OBJECT;
    }

    /**
     * @param object $resolver Resolver instance.
     * @return string
     */
    private static function classBasename(object $resolver): string
    {
        $class = get_class($resolver);
        $parts = explode('\\', $class);
        return (string) end($parts);
    }

    /**
     * @param array<int,mixed> $languages
     * @return string[]
     */
    private static function normalizeLanguages(array $languages): array
    {
        $normalized = [];

        foreach ($languages as $language) {
            if (!is_string($language)) {
                continue;
            }

            $language = trim($language);
            if ($language === '') {
                continue;
            }

            $normalized[] = $language;
        }

        return array_values(array_unique($normalized));
    }
}
