import { createI18n } from 'vue-i18n';
import messages from '@intlify/unplugin-vue-i18n/messages';
import type { I18nOptions, IntlDateTimeFormat, IntlNumberFormat } from 'vue-i18n';

export const allLocales = [
    { code: 'en', name: 'English' },
    { code: 'de', name: 'Deutsch' },
    { code: 'fr', name: 'Français' },
];

const dateTimeFormatsTemplate: IntlDateTimeFormat = {
    datetime: {
        hour: 'numeric',
        minute: 'numeric',
        second: 'numeric',
        year: 'numeric',
        month: 'numeric',
        day: 'numeric',
        hour12: false,
    },
};

const numberFormatTemplate: IntlNumberFormat = {
    decimal: {
        style: 'decimal',
    },
    decimalNoDigits: {
        style: 'decimal',
        minimumFractionDigits: 0,
        maximumFractionDigits: 0,
    },
    decimalOneDigit: {
        style: 'decimal',
        minimumFractionDigits: 1,
        maximumFractionDigits: 1,
    },
    decimalTwoDigits: {
        style: 'decimal',
        minimumFractionDigits: 2,
        maximumFractionDigits: 2,
    },
    percent: {
        style: 'percent',
    },
    percentOneDigit: {
        style: 'percent',
        minimumFractionDigits: 1,
        maximumFractionDigits: 1,
    },
    byte: {
        style: 'unit',
        unit: 'byte',
    },
    kilobyte: {
        style: 'unit',
        unit: 'kilobyte',
    },
    megabyte: {
        style: 'unit',
        unit: 'megabyte',
    },
    celsius: {
        style: 'unit',
        unit: 'celsius',
        maximumFractionDigits: 1,
    },
};

export const dateTimeFormats: I18nOptions['datetimeFormats'] = {};
export const numberFormats: I18nOptions['numberFormats'] = {};

allLocales.forEach((locale) => {
    dateTimeFormats[locale.code] = dateTimeFormatsTemplate;
    numberFormats[locale.code] = numberFormatTemplate;
});

export const i18n = createI18n({
    legacy: false,
    globalInjection: true,
    locale: navigator.language.split('-')[0],
    fallbackLocale: allLocales[0]?.code ?? 'en',
    messages,
    datetimeFormats: dateTimeFormats,
    numberFormats: numberFormats,
});

const dynamicLocales = await loadAvailLocales();
allLocales.push(...dynamicLocales);

if (localStorage.getItem('locale')) {
    setLocale(localStorage.getItem('locale') || 'en');
} else {
    localStorage.setItem('locale', i18n.global.locale.value);
}

// Set new locale.
export async function setLocale(locale: string) {
    // Load locale if not available yet.
    if (!i18n.global.availableLocales.includes(locale)) {
        const messages = await loadLocale(locale);

        // fetch() error occurred.
        if (messages === undefined) {
            i18n.global.locale.value = allLocales[0]?.code ?? 'en';
            return;
        }

        // Add locale.
        i18n.global.setLocaleMessage(locale, messages.webapp);
        i18n.global.setNumberFormat(locale, numberFormatTemplate);
        i18n.global.setDateTimeFormat(locale, dateTimeFormatsTemplate);
    }

    // Set locale.
    i18n.global.locale.value = locale;
    localStorage.setItem('locale', i18n.global.locale.value);
}

// Fetch locale.
async function loadLocale(locale: string) {
    return fetch(`/api/i18n/language?code=${locale}`)
        .then((response) => {
            if (response.ok) {
                return response.json();
            }
            throw new Error('Something went wrong!');
        })
        .catch((error) => {
            console.error(error);
        });
}

// Fetch available locales
async function loadAvailLocales() {
    return fetch('/api/i18n/languages')
        .then((response) => {
            if (response.ok) {
                return response.json();
            }
            throw new Error('Something went wrong!');
        })
        .catch((error) => {
            console.error(error);
        });
}
