import { Env } from "@vertesia/ui/env";
import { onAuthStateChanged } from "firebase/auth";
import { ReactNode, useEffect, useRef, useState } from "react";
import { STSError, UserNotFoundError, getComposableToken } from "./auth/composable";
import { shouldRedirectToCentralAuth } from "./auth/domainRouting";
import { getFirebaseAuth } from "./auth/firebase";
import { useAuthState } from "./auth/useAuthState";
import { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY, UserSession, UserSessionContext } from "./UserSession";

const CENTRAL_AUTH_REDIRECT = "https://internal-auth.vertesia.app/";

interface UserSessionProviderProps {
    children: ReactNode | ReactNode[];
}
export function UserSessionProvider({ children }: UserSessionProviderProps) {
    const hashParams = new URLSearchParams(location.hash.substring(1));
    const token = hashParams.get("token");
    const state = hashParams.get("state");
    const [session, setSession] = useState<UserSession>(new UserSession());
    const { generateState, verifyState, clearState } = useAuthState();
    const hasInitiatedAuthRef = useRef(false);

    const redirectToCentralAuth = (projectId?: string, accountId?: string) => {
        const url = new URL(`${CENTRAL_AUTH_REDIRECT}?sts=${Env.endpoints.sts ?? "https://sts.vertesia.io"}`);
        const currentUrl = new URL(window.location.href);
        currentUrl.hash = "";
        if (projectId) currentUrl.searchParams.set("p", projectId);
        if (accountId) currentUrl.searchParams.set("a", accountId);
        url.searchParams.set("redirect_uri", currentUrl.toString());
        url.searchParams.set("state", generateState());
        location.replace(url.toString());
    };

    useEffect(() => {
        // Make this effect idempotent - only run auth flow once
        if (hasInitiatedAuthRef.current) {
            console.log("Auth: skipping duplicate auth flow initiation");
            return;
        }
        hasInitiatedAuthRef.current = true;

        console.log("Auth: starting auth flow");
        Env.logger.info("Starting auth flow");
        const currentUrl = new URL(window.location.href);
        const selectedAccount =
            currentUrl.searchParams.get("a") ?? localStorage.getItem(LastSelectedAccountId_KEY) ?? undefined;
        const selectedProject =
            currentUrl.searchParams.get("p") ??
            localStorage.getItem(LastSelectedProjectId_KEY + "-" + selectedAccount) ??
            undefined;
        console.log("Auth: selected account", selectedAccount);
        console.log("Auth: selected project", selectedProject);
        Env.logger.info("Selected account and project", {
            vertesia: {
                account_id: selectedAccount,
                project_id: selectedProject,
            },
        });

        if (token && state) {
            session.setSession = setSession;
            const validationError = verifyState(state);
            if (validationError) {
                console.error(`Auth: invalid state: ${validationError}`);
                Env.logger.error(`Invalid state: ${validationError}`, {
                    vertesia: {
                        state: state,
                    },
                });
                redirectToCentralAuth();
            } else {
                clearState()
            }
            getComposableToken(selectedAccount, selectedProject, token, false, shouldRedirectToCentralAuth())
                .then((res) => {
                    session.login(res.rawToken).then(() => {
                        setSession(session.clone());
                        //cleanup the hash
                        window.location.hash = "";
                    });
                })
                .catch((err) => {
                    // Don't redirect to central auth for UserNotFoundError - let signup flow handle it
                    if (err instanceof UserNotFoundError) {
                        console.log("User not found - will trigger signup flow", err);
                        session.isLoading = false;
                        session.authError = err;
                        setSession(session.clone());
                        return;
                    }

                    if (err instanceof STSError) {
                        console.error("STS error during token exchange", err);
                        Env.logger.error("STS error during token exchange", {
                            vertesia: {
                                account_id: selectedAccount,
                                project_id: selectedProject,
                                sts_url: err.stsURL,
                                error: err,
                            },
                        });
                        window.alert("Authentication failed due to an issue with the authentication service. Please try again later.");
                        session.logout();
                        setSession(session.clone());
                        window.location.hash = "";
                        return;
                    }

                    console.error("Failed to fetch user token from studio, redirecting to central auth", err);
                    Env.logger.error("Failed to fetch user token from studio, redirecting to central auth", {
                        vertesia: {
                            error: err,
                        },
                    });
                    redirectToCentralAuth();
                });
            return;
        } else {
            // If the current host is not in the Firebase allowlist, central auth owns sign-in.
            if (!session.isLoggedIn()) {
                console.log("Auth: not logged in & no token/state");
                Env.logger.info("Not logged in & no token/state", {
                    vertesia: {
                        account_id: selectedAccount,
                        project_id: selectedProject,
                    },
                });
                if (shouldRedirectToCentralAuth()) {
                    console.log(
                        "Auth: host is not in Firebase auth allowlist, redirecting to central auth with selection",
                        selectedAccount,
                        selectedProject,
                    );
                    Env.logger.info("Redirecting to central auth with selection", {
                        vertesia: {
                            account_id: selectedAccount,
                            project_id: selectedProject,
                        },
                    });
                    redirectToCentralAuth();
                    return; // Don't register onAuthStateChanged listener when redirecting
                } else {
                    console.log("Auth: host is in Firebase auth allowlist");
                    Env.logger.info("Host is in Firebase auth allowlist", {
                        vertesia: {
                            account_id: selectedAccount,
                            project_id: selectedProject,
                        },
                    });
                }
            }
        }

        return onAuthStateChanged(getFirebaseAuth(), async (firebaseUser) => {
            if (firebaseUser) {
                console.log("Auth: successful login with firebase");
                Env.logger.info("Successful login with firebase", {
                    vertesia: {
                        account_id: selectedAccount,
                        project_id: selectedProject,
                    },
                });
                session.setSession = setSession;
                await getComposableToken(selectedAccount, selectedProject, undefined, false, shouldRedirectToCentralAuth())
                    .then((res) => {
                        session.login(res.rawToken).then(() => setSession(session.clone()));
                    })
                    .catch((err) => {
                        console.error("Failed to fetch user token from studio", err);
                        Env.logger.error("Failed to fetch user token from studio", {
                            vertesia: {
                                account_id: selectedAccount,
                                project_id: selectedProject,
                                error: err,
                            },
                        });
                        if (!(err instanceof UserNotFoundError)) session.logout();
                        session.isLoading = false;
                        session.authError = err;
                        setSession(session.clone());
                    });
            } else {
                // anonymous user
                console.log("Auth: using anonymous user");
                Env.logger.info("Using anonymous user", {
                    vertesia: {
                        account_id: selectedAccount,
                        project_id: selectedProject,
                    },
                });
                session.client.withAuthCallback(undefined);
                session.logout();
                setSession(session.clone());
            }
        });
    }, []);

    return <UserSessionContext.Provider value={session}>{children}</UserSessionContext.Provider>;
}
