<?php

namespace App\Modules\Settings\Localization\Services;

use App\Modules\Settings\Localization\DTOs\TranslationData;
use App\Modules\Settings\Localization\Models\Translation;
use App\Modules\Settings\Localization\Repositories\TranslationRepository;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Cache;

class TranslationService
{
    private const CACHE_PREFIX = 'translations:locale:';

    public function __construct(
        private readonly TranslationRepository $repository,
        private readonly LanguageService $languageService,
    ) {}

    public function translate(string $key, array $replace = [], ?string $locale = null): string
    {
        $locale = $locale ?: app()->getLocale();

        if ($value = $this->lookup($locale, $key)) {
            return $this->applyReplacements($value, $replace);
        }

        $default = $this->languageService->defaultCode();
        if ($locale !== $default && ($value = $this->lookup($default, $key))) {
            return $this->applyReplacements($value, $replace);
        }

        $fallback = trans($key, $replace, $locale);
        if (is_string($fallback) && $fallback !== $key) {
            return $fallback;
        }

        return $key;
    }

    public function create(TranslationData $data): Translation
    {
        $translation = $this->repository->create($data->toArray());
        $this->forgetLocale($data->locale);

        return $translation;
    }

    public function update(Translation $translation, TranslationData $data): Translation
    {
        $previousLocale = $translation->locale;
        $this->repository->update($translation, $data->toArray());
        $translation->refresh();

        $this->forgetLocale($previousLocale);
        if ($previousLocale !== $data->locale) {
            $this->forgetLocale($data->locale);
        }

        return $translation;
    }

    public function delete(Translation $translation): void
    {
        $locale = $translation->locale;
        $this->repository->delete($translation);
        $this->forgetLocale($locale);
    }

    public function paginate(array $filters): LengthAwarePaginator
    {
        return $this->repository->paginate($filters);
    }

    /**
     * @return array<int, string>
     */
    public function groups(): array
    {
        return $this->repository->distinctGroups();
    }

    public function forgetLocale(string $locale): void
    {
        Cache::forget(self::CACHE_PREFIX.$locale);
    }

    private function lookup(string $locale, string $key): ?string
    {
        $map = Cache::rememberForever(
            self::CACHE_PREFIX.$locale,
            fn () => $this->repository->mapForLocale($locale),
        );

        return $map[$key] ?? null;
    }

    private function applyReplacements(string $value, array $replace): string
    {
        foreach ($replace as $search => $replacement) {
            $value = str_replace([':'.$search, ':'.ucfirst($search), ':'.strtoupper($search)], [$replacement, ucfirst((string) $replacement), strtoupper((string) $replacement)], $value);
        }

        return $value;
    }
}
