import { createContext, useContext, useEffect, useRef, useState, useCallback, type ReactNode } from 'react'
import { SupabaseAuthService } from './SupabaseAuthService'
import { supabase } from '@/lib/supabase'
import type { AuthUser } from './types'

interface AuthContextValue {
  user: AuthUser | null
  loading: boolean
  isProfileLoaded: boolean
  signIn: () => Promise<void>
  signInWithEmailPassword: (email: string, password: string) => Promise<{ error: string | null }>
  signOut: () => Promise<void>
  updateUser: (updates: Partial<Pick<AuthUser, 'name' | 'company'>>) => void
  pendingPasswordReset: boolean
  clearPasswordReset: () => void
}

const AuthContext = createContext<AuthContextValue | null>(null)

const authService = new SupabaseAuthService()

// Lee el usuario almacenado en localStorage SIN hacer llamadas de red.
// Supabase v2 usa la clave sb-{project_ref}-auth-token.
// Permite renderizar la app inmediatamente sin esperar la verificación async de sesión.
function getUserFromStorage(): AuthUser | null {
  try {
    const key = Object.keys(localStorage).find(
      (k) => k.startsWith('sb-') && k.endsWith('-auth-token')
    )
    if (!key) return null
    const stored = JSON.parse(localStorage.getItem(key) ?? 'null')
    const u = stored?.user
    if (!u?.id) return null
    const email = (u.email as string) ?? ''
    return {
      id: u.id as string,
      email,
      name: (u.user_metadata?.full_name as string | undefined) || email,
      avatarUrl: u.user_metadata?.avatar_url as string | undefined,
      platformRole: email.endsWith('@inquality.com.py') ? 'platform_admin' : 'guest',
    }
  } catch {
    return null
  }
}

// Detecta si la URL tiene un callback de OAuth (token en el hash o code en query).
// En ese caso NO usar localStorage — dejar que Supabase procese el hash primero.
function hasOAuthCallback(): boolean {
  const hash = window.location.hash
  const search = window.location.search
  return (
    hash.includes('access_token') ||
    hash.includes('refresh_token') ||
    search.includes('code=')
  )
}

export function AuthProvider({ children }: { children: ReactNode }) {
  // Si hay un OAuth callback en la URL, no leer localStorage (el token aún no está ahí).
  // Supabase lo procesará en onAuthStateChange y actualizará el estado.
  const isOAuthRedirect = hasOAuthCallback()
  const [user, setUser] = useState<AuthUser | null>(
    isOAuthRedirect ? null : getUserFromStorage()
  )
  // Si es un OAuth redirect, mantener loading=true hasta que Supabase procese el token.
  const [loading, setLoading] = useState(isOAuthRedirect)
  const [pendingPasswordReset, setPendingPasswordReset] = useState(false)
  const [isProfileLoaded, setIsProfileLoaded] = useState(false)
  // Ref para comparar id entre eventos de auth y NO resetear isProfileLoaded en eventos
  // como TOKEN_REFRESHED que llegan con el mismo usuario. Sin esto, si el evento llega
  // después de que syncProfileFromDB completó, isProfileLoaded queda en false para siempre.
  const lastSyncedUserIdRef = useRef<string | null>(
    isOAuthRedirect ? null : (getUserFromStorage()?.id ?? null)
  )

  useEffect(() => {
    // Verificar y sincronizar con Supabase en background.
    // Si la sesión expiró o fue revocada, onAuthStateChange llamará callback(null)
    // y el router redirigirá a /login.
    const unsubscribe = authService.onAuthStateChange((u) => {
      const prevId = lastSyncedUserIdRef.current
      lastSyncedUserIdRef.current = u?.id ?? null
      setUser(u)
      setLoading(false)
      if (!u) {
        // Logout → nada que sincronizar
        setIsProfileLoaded(true)
      } else if (u.id !== prevId) {
        // Usuario diferente → requiere nueva sincronización con DB
        setIsProfileLoaded(false)
      }
      // Mismo usuario (TOKEN_REFRESHED, INITIAL_SESSION, etc.) → preservar isProfileLoaded
    })
    return () => unsubscribe()
  }, [])

  // Suscripción directa para PASSWORD_RECOVERY (no pasa por authService para evitar
  // mezclar el flujo normal con el de reset de contraseña).
  useEffect(() => {
    const { data: { subscription } } = supabase.auth.onAuthStateChange((event) => {
      if (event === 'PASSWORD_RECOVERY') {
        setPendingPasswordReset(true)
      }
    })
    return () => subscription.unsubscribe()
  }, [])

  // Sincronización con tabla users FUERA del lock de auth.
  // Se ejecuta al cambiar de usuario (login/logout), NO en cada updateUser().
  // user?.id es primitivo estable: no cambia cuando se edita nombre o empresa.
  useEffect(() => {
    if (!user?.id) return
    const userId = user.id
    const capturedUser = user

    // 6s timeout: si el servidor no responde, la señal de abort cancela las queries
    // y libera el processLock de Supabase antes de que bloquee loads de biblioteca/workspace.
    const controller = new AbortController()
    const timeoutId = setTimeout(() => controller.abort(), 6000)

    ;(async () => {
      try {
        // Upsert idempotente: crea la fila si no existe (primer login),
        // ignoreDuplicates evita sobreescribir name/company editados posteriormente.
        await authService.upsertUserOnLogin(capturedUser, controller.signal)
        // Leer platform_role, org_id, name y company desde la tabla (sobrescriben la heurística de email).
        const profile = await authService.syncProfileFromDB(userId, controller.signal)
        if (profile) {
          setUser((prev) =>
            prev?.id === userId
              ? {
                  ...prev,
                  name: profile.name || prev.name,
                  company: profile.company,
                  platformRole: profile.platformRole,
                  orgId: profile.orgId,
                }
              : prev
          )
        }
      } catch (err) {
        if (err instanceof Error && err.name === 'AbortError') return
        console.error('Error al sincronizar perfil:', err)
      } finally {
        clearTimeout(timeoutId)
        setIsProfileLoaded(true)
      }
    })()

    return () => {
      controller.abort()
      clearTimeout(timeoutId)
    }
  }, [user?.id]) // eslint-disable-line react-hooks/exhaustive-deps

  const signIn = useCallback(() => authService.signInWithGoogle(), [])

  const signInWithEmailPassword = useCallback(
    (email: string, password: string) => authService.signInWithEmailPassword(email, password),
    []
  )

  const signOut = useCallback(async () => {
    await authService.signOut()
    setUser(null)
    setPendingPasswordReset(false)
  }, [])

  const updateUser = useCallback((updates: Partial<Pick<AuthUser, 'name' | 'company'>>) => {
    setUser((prev) => prev ? { ...prev, ...updates } : prev)
  }, [])

  const clearPasswordReset = useCallback(() => setPendingPasswordReset(false), [])

  return (
    <AuthContext.Provider value={{
      user,
      loading,
      isProfileLoaded,
      signIn,
      signInWithEmailPassword,
      signOut,
      updateUser,
      pendingPasswordReset,
      clearPasswordReset,
    }}>
      {children}
    </AuthContext.Provider>
  )
}

export function useAuth(): AuthContextValue {
  const ctx = useContext(AuthContext)
  if (!ctx) throw new Error('useAuth debe usarse dentro de AuthProvider')
  return ctx
}
