// Locales.ts
import i18next from 'i18next';
import ICU from 'i18next-icu';
import { Assets } from 'pixi.js';

import type { Service } from '../types';
import type { i18n as I18n, InitOptions, Module } from 'i18next';

type LocaleResources = Record<string, { translation: Record<string, unknown> }>;

/** Handles localisation lookups backed by PIXI's asset loader and i18next. */
export default class Locales implements Service {
    public name = 'Locales';
    public readonly serviceType = 'locales';

    protected _lang: string;
    protected _defaultLocale: string;
    protected _resultLocale: string | null = null;

    // Используем тип интерфейса I18n, а не i18n.i18n
    public readonly _i18n: I18n;

    constructor(lang: string, defaultLocale: string) {
        this._lang = lang;
        this._defaultLocale = defaultLocale;
        this._i18n = i18next.createInstance();
    }

    public get currentLang(): string | undefined {
        const langs = Assets.get<string[]>('translations_config') ?? [];
        return langs.find(
          (lang) => lang.toLowerCase() === this._i18n.language?.toLowerCase(),
        );
    }

    public async load(): Promise<void> {
        this._resultLocale = this.getResultLocale();
        const resources = await this.loadLocale(this._resultLocale);
        await this.applyI18n(resources);
    }

    protected async loadLocale(lang: string): Promise<LocaleResources> {
        const resources: LocaleResources = {};
        const path = lang === 'en' ? 'translations.json' : `locales/${lang}.json`;
        const gamePath = `translations/${path}`;
        const sdkPath = `shared-translations/${path}`;

        const [gameTranslations, sdkTranslations] = await Promise.all([
            Assets.load<Record<string, unknown>>(gamePath),
            Assets.load<Record<string, unknown>>(sdkPath),
        ]);

        resources[lang.toLowerCase()] = {
            translation: {
                ...(sdkTranslations ?? {}),
                ...(gameTranslations ?? {}),
            },
        };

        return resources;
    }

    protected async applyI18n(resources: LocaleResources): Promise<void> {
        // Если у ICU нет типов, см. декларацию ниже; каст к Module безопасен для .use(...)
        await this._i18n.use(ICU as unknown as Module).init({
            lng: this._resultLocale ?? this._lang,
            lowerCaseLng: true,
            resources,
            returnNull: false,
            returnEmptyString: false,
            missingKeyHandler: () => {},
        } as InitOptions);
    }

    protected getResultLocale(): string {
        const config = Assets.get<string[]>('translations_config') ?? [];
        const hasLocale = config.includes(this._lang);
        const hasDefaultLocale = config.includes(this._defaultLocale);

        const resultLocale = hasLocale
          ? this._lang
          : hasDefaultLocale
            ? this._defaultLocale
            : null;

        if (resultLocale == null) {
            throw new Error(
              `There is no locale available l:${this._lang} d:${this._defaultLocale}`,
            );
        }

        return resultLocale;
    }

    public get(key: string, count?: number): string {
        const translated = this._i18n.t(key, { count });

        if (translated == null) {
            // eslint-disable-next-line no-console
            console.log(`There is no translation for the key: ${key}`);
            return key;
        }

        return translated;
    }

    public dispose(): void {
        // У i18next off(event, listener). Если нужно снять все — храните ссылки и снимайте явно.
        // Здесь оставим "мягко", без жёстких типов:
        (this._i18n as unknown as { off?: (...args: any[]) => void }).off?.();
    }
}
