import React, { createContext, useContext, useEffect, useState, useCallback, useMemo } from "react";
import { supabase } from "@/integrations/supabase/client";
import type { User, Session } from "@supabase/supabase-js";
import type { Enums, Tables } from "@/integrations/supabase/types";

type AppRole = Enums<"app_role">;

interface AuthContextType {
  user: User | null;
  session: Session | null;
  profile: Tables<"profiles"> | null;
  userRole: { role: AppRole } | null;
  loading: boolean;
  isAdmin: boolean;
  isStaff: boolean;
  isHomeowner: boolean;
  isRvBoatLot: boolean;
  isBoardMember: boolean;
  isMasterBoardMember: boolean;
  isAssociationManagement: boolean;
  isArcMember: boolean;
  // View-as (admin only)
  realIsAdmin: boolean;
  viewAsRole: AppRole | null;
  isViewingAs: boolean;
  setViewAsRole: (role: AppRole | null) => void;
  clearViewAsRole: () => void;
  signOut: () => Promise<void>;
  logout: (redirect?: boolean, reason?: string) => Promise<void>;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);
const VIEW_AS_KEY = "lovable.viewAsRole";

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [session, setSession] = useState<Session | null>(null);
  const [profile, setProfile] = useState<Tables<"profiles"> | null>(null);
  const [roles, setRoles] = useState<AppRole[]>([]);
  const [loading, setLoading] = useState(true);
  const [viewAsRole, setViewAsRoleState] = useState<AppRole | null>(() => {
    if (typeof window === "undefined") return null;
    return (sessionStorage.getItem(VIEW_AS_KEY) as AppRole | null) || null;
  });

  const clearAuthState = useCallback(() => {
    setUser(null);
    setSession(null);
    setProfile(null);
    setRoles([]);
  }, []);

  const fetchUserData = useCallback(async (userId: string) => {
    const [profileRes, rolesRes] = await Promise.all([
      supabase.from("profiles").select("*").eq("user_id", userId).single(),
      supabase.from("user_roles").select("role").eq("user_id", userId),
    ]);
    if (profileRes.data) setProfile(profileRes.data);
    if (rolesRes.data) setRoles(rolesRes.data.map((r) => r.role));
  }, []);

  useEffect(() => {
    const initAuth = async () => {
      const { data: { session: currentSession }, error } = await supabase.auth.getSession();

      if (error) {
        if (error.code === "refresh_token_not_found" || error.message?.includes("Invalid Refresh Token")) {
          await supabase.auth.signOut({ scope: "local" });
        }
        clearAuthState();
        setLoading(false);
        return;
      }

      setSession(currentSession);
      setUser(currentSession?.user ?? null);
      if (currentSession?.user) {
        await fetchUserData(currentSession.user.id);
      }
      setLoading(false);
    };

    void initAuth();

    const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, currentSession) => {
      setSession(currentSession);
      setUser(currentSession?.user ?? null);
      if (currentSession?.user) {
        void fetchUserData(currentSession.user.id);
      } else {
        clearAuthState();
        // Clear view-as on sign-out
        try { sessionStorage.removeItem(VIEW_AS_KEY); } catch { /* noop */ }
        setViewAsRoleState(null);
      }
      setLoading(false);
    });

    return () => subscription.unsubscribe();
  }, [clearAuthState, fetchUserData]);

  const realIsAdmin = roles.includes("admin");

  const setViewAsRole = useCallback((role: AppRole | null) => {
    if (!realIsAdmin) return;
    if (role) {
      try { sessionStorage.setItem(VIEW_AS_KEY, role); } catch { /* noop */ }
    } else {
      try { sessionStorage.removeItem(VIEW_AS_KEY); } catch { /* noop */ }
    }
    setViewAsRoleState(role);
  }, [realIsAdmin]);

  const clearViewAsRole = useCallback(() => setViewAsRole(null), [setViewAsRole]);

  // If non-admin somehow has view-as set (e.g. role downgraded), clear it
  useEffect(() => {
    if (viewAsRole && !realIsAdmin) {
      try { sessionStorage.removeItem(VIEW_AS_KEY); } catch { /* noop */ }
      setViewAsRoleState(null);
    }
  }, [viewAsRole, realIsAdmin]);

  const signOut = useCallback(async () => {
    try { sessionStorage.removeItem(VIEW_AS_KEY); } catch { /* noop */ }
    setViewAsRoleState(null);
    await supabase.auth.signOut();
    clearAuthState();
  }, [clearAuthState]);

  const value = useMemo<AuthContextType>(() => {
    const isViewingAs = !!viewAsRole && realIsAdmin;
    // Effective roles: when viewing-as, simulate ONLY the chosen role
    const effective: AppRole[] = isViewingAs ? [viewAsRole as AppRole] : roles;
    const primaryRole = effective[0] ?? null;

    const isAdmin = effective.includes("admin");
    const isStaff = isAdmin || effective.includes("manager") || effective.includes("employee");
    const isRvBoatLot = effective.includes("rv_boat_lot" as AppRole);
    const isAssociationManagementRole = effective.includes("association_management");
    const isHomeowner = effective.includes("homeowner") || isRvBoatLot || isAssociationManagementRole;
    const isBoardMember = effective.includes("board_member");
    const isMasterBoardMember = effective.includes("master_board_member" as AppRole);
    const isArcMember = effective.includes("arc_member" as AppRole);

    return {
      user,
      session,
      profile,
      userRole: primaryRole ? { role: primaryRole } : null,
      loading,
      isAdmin,
      isStaff,
      isHomeowner,
      isRvBoatLot,
      isBoardMember,
      isMasterBoardMember,
      isAssociationManagement: isAssociationManagementRole,
      isArcMember,
      realIsAdmin,
      viewAsRole,
      isViewingAs,
      setViewAsRole,
      clearViewAsRole,
      signOut,
      logout: signOut,
    };
  }, [user, session, profile, roles, loading, viewAsRole, realIsAdmin, signOut, setViewAsRole, clearViewAsRole]);

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

export function useAuth() {
  const context = useContext(AuthContext);
  if (context === undefined) {
    throw new Error("useAuth must be used within an AuthProvider");
  }
  return context;
}
