/*
 * Copyright (C) Contributors to the Suwayomi project
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

import type { ISOLanguage } from '@/base/IsoLanguages.ts';
import { IsoLanguages } from '@/base/IsoLanguages.ts';
import { i18nResources } from '@/i18n';
import { AppStorage } from '@/lib/storage/AppStorage.ts';

export type LanguageObject = ISOLanguage & { orgCode: string; isoCode: string };

export const DEFAULT_LANGUAGE = 'en';

export const SELECTED_LANGUAGE_CODE_KEY = 'i18n:selected-language';

// source: https://github.com/i18next/i18next/blob/485b4ec8183952b3de8fe5e79dff6467c3afd9d3/src/i18next.js#L561
const RTL_LANGUAGES = [
    'ar',
    'shu',
    'sqr',
    'ssh',
    'xaa',
    'yhd',
    'yud',
    'aao',
    'abh',
    'abv',
    'acm',
    'acq',
    'acw',
    'acx',
    'acy',
    'adf',
    'ads',
    'aeb',
    'aec',
    'afb',
    'ajp',
    'apc',
    'apd',
    'arb',
    'arq',
    'ars',
    'ary',
    'arz',
    'auz',
    'avl',
    'ayh',
    'ayl',
    'ayn',
    'ayp',
    'bbz',
    'pga',
    'he',
    'iw',
    'ps',
    'pbt',
    'pbu',
    'pst',
    'prp',
    'prd',
    'ug',
    'ur',
    'ydd',
    'yds',
    'yih',
    'ji',
    'yi',
    'hbo',
    'men',
    'xmn',
    'fa',
    'jpr',
    'peo',
    'pes',
    'prs',
    'dv',
    'sam',
    'ckb',
];

export function getISOLanguageFor(code: string, orgCode: string = code, isoCode: string = code): LanguageObject | null {
    if (IsoLanguages[code]) {
        return {
            ...IsoLanguages[code],
            orgCode,
            isoCode,
        };
    }

    return null;
}

export function getISOLanguage(code: string): LanguageObject | null {
    return (
        getISOLanguageFor(code) ??
        getISOLanguageFor(code.toLowerCase(), code) ??
        getISOLanguageFor(code.replace('-', '_'), code) ??
        getISOLanguageFor(code.replace('_', '-'), code) ??
        getISOLanguageFor(code.split('-')[0], code) ??
        getISOLanguageFor(code.split('_')[0], code)
    );
}

const toUniqueISOLanguageCodes = (codes: string[]): string[] => {
    const languages = codes.map((code) => getISOLanguage(code)).filter((code) => code !== null);
    const languagesByIsoCode = Object.groupBy(languages, (language) => language.isoCode);

    return Object.entries(languagesByIsoCode)
        .filter(([, languagesOfIsoCode]) => !!languagesOfIsoCode?.length)
        .map(([, languagesOfIsoCode]) => languagesOfIsoCode![0].orgCode);
};

export function getPreferredISOLanguageCodes(): readonly string[] {
    const preferredLanguages = toUniqueISOLanguageCodes([...navigator.languages]).map(
        (language) => getISOLanguage(language)?.isoCode ?? language,
    );

    if (!preferredLanguages.length) {
        return [DEFAULT_LANGUAGE];
    }

    return preferredLanguages;
}

export function getLanguageReadingDirection(code: string): 'ltr' | 'rtl' {
    const language = getISOLanguage(code);

    if (code.toLowerCase().includes('-latn') || language?.isoCode.includes('-latn')) {
        return 'ltr';
    }

    if (code.toLowerCase().includes('-arab') || language?.isoCode.toLowerCase().includes('-arab')) {
        return 'rtl';
    }

    if (RTL_LANGUAGES.includes(code) || RTL_LANGUAGES.includes(language?.isoCode as string)) {
        return 'rtl';
    }

    return 'ltr';
}

export function detectLocale(): string {
    const storedLanguage = AppStorage.local.getItem(SELECTED_LANGUAGE_CODE_KEY);
    const preferredLanguages = getPreferredISOLanguageCodes();
    const languageCodes = [storedLanguage, ...preferredLanguages];

    const normalizedLanguageCodes = languageCodes
        .filter((code) => code !== null)
        .filter((code) => getISOLanguage(code))
        .filter((code) => i18nResources.includes(code as (typeof i18nResources)[number]));

    return normalizedLanguageCodes[0] ?? DEFAULT_LANGUAGE;
}
