import React, {useEffect} from "react";
import {DefaultTheme, ThemeProvider} from "@react-navigation/native";
import {
    Manrope_200ExtraLight,
    Manrope_300Light,
    Manrope_400Regular,
    Manrope_500Medium,
    Manrope_600SemiBold,
    Manrope_700Bold,
    Manrope_800ExtraBold,
    useFonts,
} from "@expo-google-fonts/manrope";
import {
    PlusJakartaSans_200ExtraLight,
    PlusJakartaSans_200ExtraLight_Italic,
    PlusJakartaSans_300Light,
    PlusJakartaSans_300Light_Italic,
    PlusJakartaSans_400Regular,
    PlusJakartaSans_400Regular_Italic,
    PlusJakartaSans_500Medium,
    PlusJakartaSans_500Medium_Italic,
    PlusJakartaSans_600SemiBold,
    PlusJakartaSans_600SemiBold_Italic,
    PlusJakartaSans_700Bold,
    PlusJakartaSans_700Bold_Italic,
    PlusJakartaSans_800ExtraBold,
    PlusJakartaSans_800ExtraBold_Italic,
} from "@expo-google-fonts/plus-jakarta-sans";
import {
    Poppins_100Thin,
    Poppins_100Thin_Italic,
    Poppins_200ExtraLight,
    Poppins_200ExtraLight_Italic,
    Poppins_300Light,
    Poppins_300Light_Italic,
    Poppins_400Regular,
    Poppins_400Regular_Italic,
    Poppins_500Medium,
    Poppins_500Medium_Italic,
    Poppins_600SemiBold,
    Poppins_600SemiBold_Italic,
    Poppins_700Bold,
    Poppins_700Bold_Italic,
    Poppins_800ExtraBold,
    Poppins_800ExtraBold_Italic,
    Poppins_900Black,
    Poppins_900Black_Italic,
} from "@expo-google-fonts/poppins";
import {Stack} from "expo-router";
import * as SplashScreen from "expo-splash-screen";
import "react-native-reanimated";
import {AuthContextProvider} from "@/contexts/AuthContext";
import {QueryClient, QueryClientProvider} from "react-query";
import {TextProps, ThemeManager, Toast, Typography,} from "react-native-ui-lib";

SplashScreen.preventAutoHideAsync();

const queryClient = new QueryClient();

if (__DEV__) {
    // functions().useEmulator("localhost", 5001);
    // firestore().useEmulator("localhost", 5471);
    // auth().useEmulator("http://localhost:9099");
}

type TextStyleBase =
    | "text10"
    | "text20"
    | "text30"
    | "text40"
    | "text50"
    | "text60"
    | "text70"
    | "text80"
    | "text90"
    | "text100";
type TextStyleModifier = "R" | "M" | "BO" | "H" | "BL" | "L";
type TextStyle = TextStyleBase | `${TextStyleBase}${TextStyleModifier}`;

type TextStyleProps = {
    [K in TextStyle]?: boolean;
};

type ExtendedTextProps = TextProps & TextStyleProps;

interface FontStyle {
    fontFamily: string;
    fontSize: number;
}

const getManropeFontStyle = (style: TextStyle): FontStyle => {
    let fontFamily: string;
    let fontSize: number;

    if (style.includes("L") || style.includes("BL"))
        fontFamily = "Manrope_300Light";
    else if (style.includes("R")) fontFamily = "Manrope_400Regular";
    else if (style.includes("M")) fontFamily = "Manrope_500Medium";
    else if (style.includes("BO") || style.includes("H"))
        fontFamily = "Manrope_700Bold";
    else {
        const baseStyle = style.slice(0, 6) as TextStyleBase;
        switch (baseStyle) {
            case "text10":
            case "text20":
                fontFamily = "Manrope_700Bold";
                break;
            case "text30":
            case "text40":
                fontFamily = "Manrope_600SemiBold";
                break;
            case "text50":
                fontFamily = "Manrope_400Regular";
                break;
            default:
                fontFamily = "Manrope_300Light";
        }
    }

    switch (style.slice(0, 6) as TextStyleBase) {
        case "text10":
            fontSize = 64;
            break;
        case "text20":
            fontSize = 50;
            break;
        case "text30":
            fontSize = 36;
            break;
        case "text40":
            fontSize = 28;
            break;
        case "text50":
            fontSize = 24;
            break;
        case "text60":
            fontSize = 20;
            break;
        case "text70":
            fontSize = 16;
            break;
        case "text80":
            fontSize = 14;
            break;
        case "text90":
            fontSize = 12;
            break;
        case "text100":
            fontSize = 10;
            break;
        default:
            fontSize = 16;
    }

    return {fontFamily, fontSize};
};

export default function RootLayout() {
    const [loaded] = useFonts({
        Manrope_200ExtraLight,
        Manrope_300Light,
        Manrope_400Regular,
        Manrope_500Medium,
        Manrope_600SemiBold,
        Manrope_700Bold,
        Manrope_800ExtraBold,
        PlusJakartaSans_200ExtraLight,
        PlusJakartaSans_300Light,
        PlusJakartaSans_400Regular,
        PlusJakartaSans_500Medium,
        PlusJakartaSans_600SemiBold,
        PlusJakartaSans_700Bold,
        PlusJakartaSans_800ExtraBold,
        PlusJakartaSans_200ExtraLight_Italic,
        PlusJakartaSans_300Light_Italic,
        PlusJakartaSans_400Regular_Italic,
        PlusJakartaSans_500Medium_Italic,
        PlusJakartaSans_600SemiBold_Italic,
        PlusJakartaSans_700Bold_Italic,
        PlusJakartaSans_800ExtraBold_Italic,
        Poppins_100Thin,
        Poppins_100Thin_Italic,
        Poppins_200ExtraLight,
        Poppins_200ExtraLight_Italic,
        Poppins_300Light,
        Poppins_300Light_Italic,
        Poppins_400Regular,
        Poppins_400Regular_Italic,
        Poppins_500Medium,
        Poppins_500Medium_Italic,
        Poppins_600SemiBold,
        Poppins_600SemiBold_Italic,
        Poppins_700Bold,
        Poppins_700Bold_Italic,
        Poppins_800ExtraBold,
        Poppins_800ExtraBold_Italic,
        Poppins_900Black,
        Poppins_900Black_Italic,
    });

    useEffect(() => {
        if (loaded) {
            SplashScreen.hideAsync();

            const typographies: Partial<Record<TextStyle, FontStyle>> = {};
            (
                [
                    "text10",
                    "text20",
                    "text30",
                    "text40",
                    "text50",
                    "text60",
                    "text70",
                    "text80",
                    "text90",
                    "text100",
                ] as const
            ).forEach((baseStyle) => {
                typographies[baseStyle] = getManropeFontStyle(baseStyle);
                (["R", "M", "BO", "H", "BL", "L"] as const).forEach((modifier) => {
                    const style = `${baseStyle}${modifier}` as TextStyle;
                    typographies[style] = getManropeFontStyle(style);
                });
            });

            Typography.loadTypographies(typographies);

            ThemeManager.setComponentTheme(
                "Text",
                (props: ExtendedTextProps) => {
                    const textStyle = (
                        Object.keys(props) as Array<keyof ExtendedTextProps>
                    ).find((key) => typographies[key as TextStyle]) as
                        | TextStyle
                        | undefined;

                    return {
                        style: [
                            Typography.text50,
                            textStyle ? typographies[textStyle] : undefined,
                        ],
                    };
                }
            );
        }
    }, [loaded]);

    if (!loaded) {
        return null;
    }

    return (
        <QueryClientProvider client={queryClient}>
            <AuthContextProvider>
                <ThemeProvider value={DefaultTheme}>
                    <Stack>
                        <Stack.Screen name="(auth)" options={{headerShown: false}}/>
                        <Stack.Screen name="(unauth)" options={{headerShown: false}}/>
                        <Stack.Screen name="+not-found"/>
                    </Stack>
                    <Toast/>
                </ThemeProvider>
            </AuthContextProvider>
        </QueryClientProvider>
    );
}
