<?php
/**
 * 2026 Paysera
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@prestashop.com so we can send you a copy immediately.
 *
 * @author Paysera <plugins@paysera.com>
 * @copyright 2026 Paysera
 * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
 * International Registered Trademark & Property of Paysera
 */

declare(strict_types=1);

namespace Paysera\PrestashopPayments\Provider;

use Paysera\CheckoutSdk\SdkFacade;
use Paysera\PrestashopPayments\Dto\TranslationsData;
use Psr\Log\LoggerInterface;

if (!defined('_PS_VERSION_')) {
    exit;
}

class TranslationsDataProvider
{
    private const SUPPORTED_FILES = ['messages.json', 'messages.php'];
    private const SOURCE_LANGUAGE = 'en';
    private const BASE_TRANSLATIONS_FILE = 'messages.en.json';

    public function __construct(
        private SdkFacade $sdkFacade,
        private LoggerInterface $logger,
        private ModulePathsProvider $modulePaths
    ) {
    }

    public function getTranslationsData(): ?TranslationsData
    {
        $sdkTranslations = $this->fetchSdkTranslations();
        $baseTranslations = $this->loadBaseTranslations();

        $merged = $this->mergeTranslations($baseTranslations, $sdkTranslations);

        if ($merged === []) {
            return null;
        }

        return new TranslationsData($merged);
    }

    /**
     * @return array<string, array<string, string>>
     */
    private function fetchSdkTranslations(): array
    {
        try {
            $translator = $this->sdkFacade
                ->getTranslationsFacade()
                ->getTranslator(\PayseraPayments::PLUGIN_NAMESPACE)
            ;

            return $this->normalizeTranslations($translator->getTranslations());
        } catch (\Throwable $exception) {
            $this->logger->error('Failed to fetch translations data', [
                'exception' => $exception->getMessage(),
                'code' => $exception->getCode(),
            ]);

            return [];
        }
    }

    /**
     * @return array<string, array<string, string>>
     */
    private function loadBaseTranslations(): array
    {
        $englishTranslations = $this->loadBaseJsonFile();

        if ($englishTranslations === []) {
            return [];
        }

        $translations = [self::SOURCE_LANGUAGE => $englishTranslations];

        foreach (\Language::getLanguages(false) as $language) {
            $languageCode = explode('-', $language['locale'])[0];

            if ($languageCode === self::SOURCE_LANGUAGE) {
                continue;
            }

            $translations[$languageCode] = $englishTranslations;
        }

        return $translations;
    }

    /**
     * @return array<string, string>
     */
    private function loadBaseJsonFile(): array
    {
        $filePath = $this->modulePaths->getTranslationsPath() . '/' . self::BASE_TRANSLATIONS_FILE;

        if (!file_exists($filePath)) {
            return [];
        }

        try {
            $content = file_get_contents($filePath);

            if ($content === false) {
                return [];
            }

            $decoded = json_decode($content, true);

            if (!is_array($decoded)) {
                $this->logger->warning('Failed to decode base translations JSON', [
                    'file' => $filePath,
                ]);

                return [];
            }

            return $decoded;
        } catch (\Throwable $exception) {
            $this->logger->warning('Failed to load base translations', [
                'exception' => $exception->getMessage(),
            ]);

            return [];
        }
    }

    /**
     * @param array<string, array<string, string>> $base
     * @param array<string, array<string, string>> $override
     *
     * @return array<string, array<string, string>>
     */
    private function mergeTranslations(array $base, array $override): array
    {
        $languages = array_unique(array_merge(array_keys($base), array_keys($override)));
        $merged = [];

        foreach ($languages as $languageCode) {
            if ($languageCode === self::SOURCE_LANGUAGE) {
                $merged[$languageCode] = array_merge(
                    $override[$languageCode] ?? [],
                    $base[$languageCode] ?? []
                );

                continue;
            }

            $merged[$languageCode] = array_merge(
                $base[$languageCode] ?? [],
                $override[$languageCode] ?? []
            );
        }

        return $merged;
    }

    /**
     * @param array<string, array<string, array<string, string>>> $rawTranslations
     *
     * @return array<string, array<string, string>>
     */
    private function normalizeTranslations(array $rawTranslations): array
    {
        $normalized = [];

        foreach ($rawTranslations as $languageCode => $files) {
            foreach (self::SUPPORTED_FILES as $fileName) {
                if (isset($files[$fileName])) {
                    $normalized[$languageCode] = $files[$fileName];

                    break;
                }
            }
        }

        return $normalized;
    }
}
