import { globalAK } from "@goauthentik/common/global";

import { LOCALES as RAW_LOCALES, enLocale } from "./definitions";
import { AkLocale } from "./types";

export const DEFAULT_LOCALE = "en";

export const EVENT_REQUEST_LOCALE = "ak-request-locale";

const TOMBSTONE = "⛼⛼tombstone⛼⛼";

// NOTE: This is the definition of the LOCALES table that most of the code uses. The 'definitions'
// file is relatively pure, but here we establish that we want the English locale to loaded when an
// application is first instantiated.

export const LOCALES = RAW_LOCALES.map((locale) =>
    locale.code === "en" ? { ...locale, locale: async () => enLocale } : locale,
);

export function getBestMatchLocale(locale: string): AkLocale | undefined {
    return LOCALES.find((l) => l.match.test(locale));
}

// This looks weird, but it's sensible: we have several candidates, and we want to find the first
// one that has a supported locale. Then, from *that*, we have to extract that first supported
// locale.

export function findSupportedLocale(candidates: string[]) {
    const candidate = candidates.find((candidate: string) => getBestMatchLocale(candidate));
    return candidate ? getBestMatchLocale(candidate) : undefined;
}

export function localeCodeFromUrl(param = "locale") {
    const url = new URL(window.location.href);
    return url.searchParams.get(param) || "";
}

// Get all locales we can, in order
// - Global authentik settings (contains user settings)
// - URL parameter
// - A requested code passed in, if any
// - Navigator
// - Fallback (en)

const isLocaleCandidate = (v: unknown): v is string =>
    typeof v === "string" && v !== "" && v !== TOMBSTONE;

export function autoDetectLanguage(userReq = TOMBSTONE, brandReq = TOMBSTONE): string {
    const localeCandidates: string[] = [
        localeCodeFromUrl("locale"),
        userReq,
        window.navigator?.language ?? TOMBSTONE,
        brandReq,
        globalAK()?.locale ?? TOMBSTONE,
        DEFAULT_LOCALE,
    ].filter(isLocaleCandidate);

    const firstSupportedLocale = findSupportedLocale(localeCandidates);

    if (!firstSupportedLocale) {
        console.debug(
            `authentik/locale: No locale found for '[${localeCandidates}.join(',')]', falling back to ${DEFAULT_LOCALE}`,
        );
        return DEFAULT_LOCALE;
    }

    return firstSupportedLocale.code;
}

export default autoDetectLanguage;
