import {
    type ReactElement,
    type ReactNode,
    useContext
} from "react";
import type ITextProps from "../components/text/type";
import {
    type LocalizeContextStateType,
    type LocalizeContextType,
    type LocalizeType
} from "../types";
import NCoreContext, {
    type ConfigType
} from "ncore-context";
import Text from "../components/text";
import {
    uuid
} from "../utils";
import defaultLocalesData from "../variants/locales/default.json";

class NCoreUIKitLocalize<T extends LocalizeType> extends NCoreContext<LocalizeContextType, ConfigType<LocalizeContextType>> {
    projectLocales?: NCoreUIKit.Locales = undefined;

    useContext = ({
        activeLocale
    }: {
        activeLocale?: NCoreUIKit.LocaleKey
    } = {}): LocalizeContextType => {
        const currentState = useContext(this.stateContext);

        if(activeLocale) {
            const activeState = this.prepare({
                activeLocale: activeLocale ? activeLocale : currentState.activeLocale
            });

            return {
                ...currentState,
                ...activeState,
                localizeWithObject: this.localizeWithObject,
                localize: this.localize
            };
        }

        return {
            ...currentState,
            localizeWithObject: this.localizeWithObject,
            localize: this.localize
        };
    };

    constructor(initialState: T) {
        const {
            initialSelectedLocale,
            projectLocales
        } = initialState;

        const initialLanguage = defaultLocalesData.find(l => l.locale === "tr-TR");

        if(!initialLanguage) {
            throw new Error("Initial Locale error!.");
        }

        super({
            localizeWithObject: () => "Localization is loading...",
            activeLocale: initialSelectedLocale ?? "tr-TR",
            localize: () => "Localization is loading...",
            translations: initialLanguage.translations,
            isRTL: initialLanguage.isRTL
        }, {
            key: "NCoreUIKitLocalize"
        });

        this.projectLocales = projectLocales;

        const activeState = this.prepare({
            activeLocale: initialSelectedLocale ?? "tr-TR"
        });

        this.state = activeState as LocalizeContextType;
    }

    prepare = (props?: {
        activeLocale?: NCoreUIKit.LocaleKey
    }): LocalizeContextStateType => {
        const locale = props && props.activeLocale ? props.activeLocale : this.state.activeLocale;

        const defaultLocale = defaultLocalesData.find(l => l.locale === locale) ?? defaultLocalesData[0]!;

        const defaultState: LocalizeContextStateType = {
            activeLocale: defaultLocale.locale as NCoreUIKit.LocaleKey,
            // localizeWithObject: this.localizeWithObject,
            translations: defaultLocale.translations,
            isRTL: defaultLocale.isRTL
            // localize: this.localize
        };

        if(!this.projectLocales || (this.projectLocales && !this.projectLocales.length)) {
            return defaultState;
        }

        const currentProjectLocale = this.projectLocales.find(l => l.locale === locale);

        if(!currentProjectLocale) {
            return defaultState;
        }

        const newState: LocalizeContextStateType = {
            activeLocale: currentProjectLocale.locale as NCoreUIKit.LocaleKey,
            // localizeWithObject: this.localizeWithObject,
            isRTL: currentProjectLocale.isRTL,
            // localize: this.localize,
            translations: {
                ...defaultLocale.translations,
                ...currentProjectLocale.translations
            }
        };

        return newState;
    };

    localizeWithObject = (
        translation: keyof NCoreUIKit.Translation,
        parameters?: Array<string | ReactNode | ReactElement>,
        props?: Array<ITextProps>
    ) => {
        try {
            let translatedText: string | ReactNode[] = String(this.state.translations[translation]);

            if(!translatedText) {
                return translation;
            }

            if(parameters && parameters.length) {
                parameters.forEach((_item, index) => {
                    if (typeof translatedText !== "string") return;

                    translatedText = translatedText!.split(`{{${index}}}`).flatMap((item) => [
                        item,
                        props && props[index] ? <Text
                            key={uuid()}
                            {...props[index]}
                        >{parameters[index]}</Text> : <Text key={uuid()}>{parameters[index]}</Text>
                    ]).slice(0, -1);
                });
            }

            return translatedText;
        } catch(e) {
            console.error(e);
            return translation;
        }
    };

    localize = (
        translation: keyof NCoreUIKit.Translation,
        parameters?: Array<string | number>
    ) => {
        try {
            let translatedText = this.state.translations[translation];

            if(!translatedText) {
                return translation;
            }

            if(parameters && parameters.length) {
                parameters.forEach((item, index) => {
                    translatedText = translatedText.replace(`{{${index}}}`, String(item));
                });
            }

            return translatedText;
        } catch(e) {
            console.error(e);
            return translation;
        }
    };

    switch = ({
        localeKey
    }: {
        localeKey: NCoreUIKit.LocaleKey
    }) => {
        const activeState = this.prepare({
            activeLocale: localeKey
        });

        this.setState(activeState);
    };

    updateProjectLocales = (newProjectLocales: NCoreUIKit.Locales, newState?: {
        activeLocale?: NCoreUIKit.LocaleKey
    }) => {
        this.projectLocales = newProjectLocales;
        const activeState = this.prepare(newState);

        this.setState(activeState);
    };
}
export default NCoreUIKitLocalize;
