import { create } from "zustand";
import { Provider, Session } from "@supabase/supabase-js";
import { supabase } from "@/lib/supabase";
import * as WebBrowser from "expo-web-browser";
import { makeRedirectUri } from "expo-auth-session";
import * as QueryParams from "expo-auth-session/build/QueryParams";
import { Linking } from "react-native";
import { QueryClient } from "@tanstack/react-query";
import { User } from "@/types/user.types";
import { api } from "@/lib/api";
import * as AppleAuthentication from "expo-apple-authentication";
import { ensurePurchasesConfigured } from "@/lib/purchases";
import { organizationBillingQueryKey } from "@/hooks/organization";

interface AuthState {
  session: Session | null;
  user: User | null;
  loading: boolean;
  initialized: boolean;
  initialize: (queryClient: QueryClient) => Promise<void>;
  setSession: (session: Session | null) => void;
  login: (email: string, password: string) => Promise<void>;
  signUp: (
    email: string,
    password: string,
    firstName: string,
    lastName: string,
    companyName: string
  ) => Promise<void>;
  performOAuth: (provider: Provider) => Promise<void>;
  signInWithApple: () => Promise<void>;
  signOut: () => Promise<void>;
  createSessionFromUrl: (url: string) => Promise<void>;
  fetchAndSetUser: (session: Session | null, queryClient?: QueryClient) => Promise<void>;
}

WebBrowser.maybeCompleteAuthSession();
const redirectTo = makeRedirectUri({ path: "/(app)/(tabs)" });

export const useAuthStore = create<AuthState>((set, get) => ({
  user: null,
  session: null,
  loading: true,
  initialized: false,
  setSession: (session: Session | null) => set({ session }),
  fetchAndSetUser: async (session: Session | null, queryClient?: QueryClient) => {
    if (!session) {
      set({ user: null });
      queryClient?.removeQueries({ queryKey: organizationBillingQueryKey });
      return;
    }

    try {
      const { data } = await api.get<User>("/api/v1/users/me", {
        headers: {
          Authorization: `Bearer ${session?.access_token}`,
        },
      });
      set({ user: data });
      await ensurePurchasesConfigured(data.id);
      await queryClient?.invalidateQueries({ queryKey: organizationBillingQueryKey });
    } catch (error) {
      console.error("Error fetching user:", error);
    }
  },
  initialize: async (queryClient: QueryClient) => {
    try {
      const {
        data: { session },
      } = await supabase.auth.getSession();

      set({
        session,
      });
      await get().fetchAndSetUser(session, queryClient);

      supabase.auth.onAuthStateChange(async (event, session) => {
        set({
          session,
        });
        await get().fetchAndSetUser(session, queryClient);
      });

      const initialUrl = await Linking.getInitialURL();
      if (initialUrl) {
        await get().createSessionFromUrl(initialUrl);
      }

      Linking.addEventListener("url", ({ url }) => {
        get().createSessionFromUrl(url);
      });
    } catch (error) {
      console.error("Auth initialization error:", error);
    } finally {
      set({ loading: false });
      set({ initialized: true });
      queryClient.invalidateQueries({ queryKey: ["user"] });
    }
  },
  login: async (email: string, password: string) => {
    const { error } = await supabase.auth.signInWithPassword({
      email,
      password,
    });
    if (error) throw error;
    set({ loading: false });
  },
  signUp: async (
    email: string,
    password: string,
    firstName: string,
    lastName: string,
    companyName: string
  ) => {
    set({ loading: true });

    try {
      const { data, error } = await supabase.auth.signUp({
        email,
        password,
        options: {
          data: {
            company_name: companyName,
            first_name: firstName,
            last_name: lastName,
            name: [firstName, lastName].filter(Boolean).join(" ").trim(),
          },
        },
      });

      if (error) {
        throw error;
      }

      if (!data.session) {
        throw new Error(
          "Impossible d'ouvrir votre session après l'inscription. Si cette adresse existe déjà, essayez de vous connecter."
        );
      }
    } finally {
      set({ loading: false });
    }
  },
  performOAuth: async (provider: Provider) => {
    const { data, error } = await supabase.auth.signInWithOAuth({
      provider,
      options: {
        redirectTo,
        skipBrowserRedirect: true,
        queryParams: {
          access_type: "offline",
          prompt: "consent",
        },
      },
    });
    if (error) throw error;

    const res = await WebBrowser.openAuthSessionAsync(data?.url ?? "", redirectTo);

    if (res.type === "success") {
      const { url } = res;
      await get().createSessionFromUrl(url);
    }
  },
  signInWithApple: async () => {
    try {
      const credential = await AppleAuthentication.signInAsync({
        requestedScopes: [
          AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
          AppleAuthentication.AppleAuthenticationScope.EMAIL,
        ],
      });

      if (credential.identityToken) {
        const {
          error,
          data: { session },
        } = await supabase.auth.signInWithIdToken({
          provider: "apple",
          token: credential.identityToken,
        });
        if (!error && session) {
          await set({ session });
        }
      } else {
        throw new Error("No identityToken.");
      }
    } catch (e) {
      console.error("Error signing in with Apple:", e);
    }
  },
  signOut: async () => {
    await supabase.auth.signOut();
    set({ loading: false, user: null, session: null });
  },
  createSessionFromUrl: async (url: string) => {
    const { params, errorCode } = QueryParams.getQueryParams(url);

    if (errorCode) throw new Error(errorCode);
    const { access_token, refresh_token } = params;

    if (!access_token) return;

    const { data, error } = await supabase.auth.setSession({
      access_token,
      refresh_token,
    });
    if (error) throw error;
    set({ session: data.session });
  },
}));
