import { createClient, type User, type Session } from '@supabase/supabase-js'
import { createContext, useContext, useEffect, useState } from 'react'

export const supabase = createClient(
  import.meta.env.VITE_SUPABASE_URL,
  import.meta.env.VITE_SUPABASE_ANON_KEY,
)

export interface SupabaseAuthState {
  isAuthenticated: boolean
  user: User | null
  claims: UserClaims | null
  roles: RolCatalogo[] | null
  login: (email: string, password: string) => Promise<void>
  logout: () => Promise<void>
  isLoading: boolean
}

export interface RolCatalogo {
  id: string
  nombre: string
  icono: string
  nombre_clase: string
  label: string
}

export type Role = string;

export type UserClaims = {
  id: string | null
  clave?: string
  nombre: string
  apellidos: string
  title?: string
  avatar?: string | null
  carrera_id?: string | null
  facultad_id?: string | null
  facultad_color?: string | null  // 🎨 NEW
  role: Role
}

const SupabaseAuthContext = createContext<SupabaseAuthState | undefined>(undefined)

export function SupabaseAuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<User | null>(null)
  const [claims, setClaims] = useState<UserClaims | null>(null)
  const [roles, setRoles] = useState<RolCatalogo[] | null>(null)
  const [isAuthenticated, setIsAuthenticated] = useState(false)
  const [isLoading, setIsLoading] = useState(true)

  useEffect(() => {
    // Función para manejar la sesión
    const handleSession = async (session: Session | null) => {
      const u = session?.user ?? null
      setUser(u)
      setIsAuthenticated(!!u)
      setClaims(await buildClaims(session))
      setIsLoading(false)
    }
  
    // Carga inicial
    supabase.auth.getSession().then(({ data: { session } }) => {
      handleSession(session)
    })

    // Carga roles catálogo
    fetchRoles().then(fetchedRoles => {
      setRoles(fetchedRoles);
    });
  
    // Suscripción a cambios de sesión
    const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => {
      handleSession(session)
    })
  
    return () => subscription.unsubscribe()
  }, [])

  const login = async (email: string, password: string) => {
    const { error } = await supabase.auth.signInWithPassword({ email, password })
    if (error?.code === 'invalid_credentials') throw new Error('Credenciales inválidas')
    else if (error) throw error
  }

  const logout = async () => {
    const { error } = await supabase.auth.signOut()
    if (error) throw error
    location.href = "/login"
  }

  return (
    <SupabaseAuthContext.Provider
      value={{ isAuthenticated, user, claims, roles, login, logout, isLoading }}
    >
      {children}
    </SupabaseAuthContext.Provider>
  )
}

export function useSupabaseAuth() {
  const context = useContext(SupabaseAuthContext)
  if (context === undefined) {
    throw new Error('useSupabaseAuth must be used within SupabaseAuthProvider')
  }
  return context
}

/* ===================== *
 * Helpers
 * ===================== */

// Obtiene los claims del usuario desde la base de datos a partir de una función en la BDD
async function buildClaims(session: Session | null): Promise<UserClaims | null> {
  // Validar sesión
  if (!session || !session.user) {
    console.warn('No session or user found');
    return null;
  }
  const u = session.user;


  try{
    const result = await supabase.rpc('obtener_claims_usuario', {
      p_user_id: u.id,
    });
    
    const data: UserClaims[] | null = result.data;
    const error = result.error;

    if (error) {
      console.error('Error al obtener la información:', error);
      throw new Error('Error al obtener la información del usuario');
    }

    console.log(data);
    if (!data || data.length === 0) {
      console.warn('No se encontró información para el usuario');
      return null;
    }

    return {
      ...data[0],
      id: null
    };
  } catch (e) {
    console.error('Error inesperado:', e);
    return null;
  }
}

async function fetchRoles(): Promise<RolCatalogo[]> {
  const { data, error } = await supabase
    .from("roles_catalogo")
    .select("id, nombre, icono, nombre_clase, label");

  if (error) {
    console.error("Error al obtener los roles:", error.message);
    return [];
  }

  return data || [];
}
