import {
  signInWithEmailAndPassword,
  signInWithPopup,
  GoogleAuthProvider,
  signOut as firebaseSignOut,
  onAuthStateChanged,
  getAuth,
  createUserWithEmailAndPassword,
} from "firebase/auth";
import { getApp, getApps, initializeApp } from "firebase/app";
import type { User } from "firebase/auth";

export const useAuth = () => {
  const user = useState<User | null>("auth-user", () => null);
  const isLoading = useState<boolean>("auth-loading", () => true);
  const error = useState<string | null>("auth-error", () => null);
  const firebaseReady = useState<boolean>("firebase-ready", () => false);
  const listenerRegistered = useState<boolean>(
    "auth-listener-registered",
    () => false
  );
  const backendUser = useState<Record<string, any> | null>(
    "auth-backend-user",
    () => null
  );

  const config = useRuntimeConfig();

  const ensureFirebaseApp = () => {
    if (!process.client) {
      return null;
    }

    if (!firebaseReady.value) {
      const firebaseConfig = {
        apiKey: config.public.firebaseApiKey,
        authDomain: config.public.firebaseAuthDomain,
        projectId: config.public.firebaseProjectId,
        storageBucket: config.public.firebaseStorageBucket,
        messagingSenderId: config.public.firebaseMessagingSenderId,
        appId: config.public.firebaseAppId,
        ...(config.public.firebaseMeasurementId
          ? { measurementId: config.public.firebaseMeasurementId }
          : {}),
      };

      if (getApps().length === 0) {
        initializeApp(firebaseConfig);
      }

      firebaseReady.value = true;
    }

    try {
      return getApp();
    } catch (err) {
      console.error("[useAuth] Failed to get Firebase app instance:", err);
      return null;
    }
  };

  const getAuthInstance = () => {
    const app = ensureFirebaseApp();
    return app ? getAuth(app) : null;
  };

  const authenticateWithBackend = async (idToken: string) => {
    try {
      const response = await $fetch<{
        token?: string;
        user?: Record<string, any> | null;
      }>("/auth/login", {
        baseURL: config.public.backendUrl,
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: {
          idToken,
        },
      });

      backendUser.value = response?.user ?? null;
      return response;
    } catch (err) {
      console.error("Backend authentication failed:", err);
      backendUser.value = null;
      throw err;
    }
  };

  const syncBackendWithToken = async (tokenProvider: () => Promise<string>) => {
    try {
      const idToken = await tokenProvider();
      await authenticateWithBackend(idToken);
    } catch (err) {
      console.warn("[useAuth] Failed to sync backend session", err);
    }
  };

  const registerListener = () => {
    if (!process.client || listenerRegistered.value) {
      return;
    }

    try {
      const auth = getAuthInstance();
      if (auth) {
        const existingUser = auth.currentUser;
        if (existingUser && !user.value) {
          user.value = existingUser;
          isLoading.value = false;
          syncBackendWithToken(() => existingUser.getIdToken());
        }

        listenerRegistered.value = true;
        onAuthStateChanged(auth, (firebaseUser) => {
          user.value = firebaseUser;
          isLoading.value = false;
          if (firebaseUser) {
            syncBackendWithToken(() => firebaseUser.getIdToken());
          } else {
            backendUser.value = null;
          }
        });
      }
    } catch (err) {
      console.error("[useAuth] Failed to initialize auth listener:", err);
      isLoading.value = false;
    }
  };

  const initAuth = () => {
    registerListener();
  };

  // Eagerly register listener when composable is used in client context
  if (process.client) {
    registerListener();
  }

  // Sign in with email and password
  const signInWithEmail = async (email: string, password: string) => {
    try {
      error.value = null;
      isLoading.value = true;

      const auth = getAuthInstance();
      if (!auth) {
        throw new Error("Firebase not initialized");
      }

      const userCredential = await signInWithEmailAndPassword(
        auth,
        email,
        password
      );
      const idToken = await userCredential.user.getIdToken();

      try {
        await authenticateWithBackend(idToken);
      } catch (backendErr) {
        console.warn(
          "[useAuth] Backend authentication failed after email login:",
          backendErr
        );
      }

      user.value = userCredential.user;
      registerListener();

      return userCredential.user;
    } catch (err: any) {
      error.value = err.message;
      throw err;
    } finally {
      isLoading.value = false;
    }
  };

  // Sign in with Google
  const signInWithGoogle = async () => {
    try {
      error.value = null;
      isLoading.value = true;

      const auth = getAuthInstance();
      if (!auth) {
        throw new Error("Firebase not initialized");
      }

      const provider = new GoogleAuthProvider();
      const userCredential = await signInWithPopup(auth, provider);
      const idToken = await userCredential.user.getIdToken();

      try {
        await authenticateWithBackend(idToken);
      } catch (backendErr) {
        console.warn(
          "[useAuth] Backend authentication failed after Google login:",
          backendErr
        );
      }

      user.value = userCredential.user;
      registerListener();

      return userCredential.user;
    } catch (err: any) {
      error.value = err.message;
      throw err;
    } finally {
      isLoading.value = false;
    }
  };

  const registerWithEmail = async (email: string, password: string) => {
    try {
      error.value = null;
      isLoading.value = true;

      const auth = getAuthInstance();
      if (!auth) {
        throw new Error("Firebase not initialized");
      }

      const userCredential = await createUserWithEmailAndPassword(
        auth,
        email,
        password
      );
      const idToken = await userCredential.user.getIdToken();

      try {
        await authenticateWithBackend(idToken);
      } catch (backendErr) {
        console.warn(
          "[useAuth] Backend authentication failed after registration:",
          backendErr
        );
      }

      user.value = userCredential.user;
      registerListener();

      return userCredential.user;
    } catch (err: any) {
      error.value = err.message;
      throw err;
    } finally {
      isLoading.value = false;
    }
  };

  // Sign out
  const signOut = async () => {
    try {
      const auth = getAuthInstance();
      if (!auth) {
        throw new Error("Firebase not initialized");
      }

      await firebaseSignOut(auth);
      user.value = null;
      backendUser.value = null;
    } catch (err: any) {
      error.value = err.message;
      throw err;
    }
  };

  // Get current user's ID token
  const getIdToken = async () => {
    if (!user.value) return null;
    return await user.value.getIdToken();
  };

  return {
    user: readonly(user),
    isLoading: readonly(isLoading),
    error: readonly(error),
    backendUser: readonly(backendUser),
    initAuth,
    signInWithEmail,
    signInWithGoogle,
    registerWithEmail,
    signOut,
    getIdToken,
  };
};
