import React, {
  createContext,
  useContext,
  useEffect,
  useMemo,
  useState,
  useCallback,
  type ReactNode,
} from "react";
import type { User as SupabaseUser } from "@supabase/supabase-js";
import { supabase } from "@/lib/supabase";
import { getActiveTableroCdcAccess, type TableroCdcUserAccess } from "@/lib/accessControl";
import { recordTableroCdcOpen } from "@/lib/appMetrics";

function getRedirectTo(): string {
  if (typeof window === "undefined") return "/tablero-cdc/";
  return new URL(import.meta.env.BASE_URL || "/", window.location.origin).toString();
}

export interface AuthUser {
  id: string;
  uid: string;
  email: string | null;
  displayName: string | null;
  photoURL: string | null;
  raw: SupabaseUser;
}

function normalizeSupabaseUser(user: SupabaseUser): AuthUser {
  const metadata = user.user_metadata || {};

  const displayName =
    metadata.full_name ||
    metadata.name ||
    metadata.display_name ||
    user.email?.split("@")[0] ||
    null;

  const photoURL = metadata.avatar_url || metadata.picture || null;

  return {
    id: user.id,
    uid: user.id,
    email: user.email ?? null,
    displayName,
    photoURL,
    raw: user,
  };
}

interface AuthContextValue {
  user: AuthUser | null;
  loading: boolean;
  error: string | null;
  isGerardo: boolean;
  canDeleteProjects: boolean;
  canManageInternalPricing: boolean;
  canControlPricingSummary: boolean;
  canManageTariffCatalog: boolean;
  canViewTeamHours: boolean;
  canCreateProjects: boolean;
  loginWithGoogle: () => Promise<void>;
  logout: () => Promise<void>;
}

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

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<AuthUser | null>(null);
  const [access, setAccess] = useState<TableroCdcUserAccess | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  const applyUser = useCallback(async (supabaseUser: SupabaseUser | null) => {
    if (!supabaseUser) {
      setUser(null);
      setAccess(null);
      return;
    }

    let nextAccess: TableroCdcUserAccess | null = null;

    try {
      nextAccess = await getActiveTableroCdcAccess(supabaseUser.email);
    } catch (accessError) {
      console.error("Error al validar acceso al Tablero CDC:", accessError);
      await supabase.auth.signOut();
      setUser(null);
      setAccess(null);
      setError(
        "No se pudo validar tu acceso al Tablero CDC. Verifica que el SQL de accesos esté ejecutado o contacta a IT.",
      );
      return;
    }

    if (!nextAccess) {
      await supabase.auth.signOut();
      setUser(null);
      setAccess(null);
      setError(
        "Tu correo no está autorizado para acceder al Tablero CDC. Solicita acceso a IT o al equipo CDC.",
      );
      return;
    }

    setUser(normalizeSupabaseUser(supabaseUser));
    setAccess(nextAccess);
    setError(null);

    // Métrica no bloqueante: una apertura por sesión autenticada/autorizada.
    void recordTableroCdcOpen();
  }, []);

  useEffect(() => {
    let mounted = true;

    supabase.auth
      .getSession()
      .then(async ({ data, error: sessionError }) => {
        if (!mounted) return;

        if (sessionError) {
          console.error("Error al recuperar sesión de Supabase:", sessionError);
          setUser(null);
          setError("No se pudo recuperar la sesión. Intenta iniciar sesión de nuevo.");
          return;
        }

        await applyUser(data.session?.user ?? null);
      })
      .catch((err: unknown) => {
        if (!mounted) return;
        console.error("Error inesperado al recuperar sesión:", err);
        setUser(null);
        setError("No se pudo recuperar la sesión. Intenta iniciar sesión de nuevo.");
      })
      .finally(() => {
        if (mounted) setLoading(false);
      });

    const { data: listener } = supabase.auth.onAuthStateChange((_event, session) => {
      setLoading(true);
      void applyUser(session?.user ?? null).finally(() => {
        if (mounted) setLoading(false);
      });
    });

    return () => {
      mounted = false;
      listener.subscription.unsubscribe();
    };
  }, [applyUser]);

  const loginWithGoogle = useCallback(async () => {
    setError(null);

    const { error: loginError } = await supabase.auth.signInWithOAuth({
      provider: "google",
      options: {
        redirectTo: getRedirectTo(),
        queryParams: {
          prompt: "select_account",
        },
      },
    });

    if (loginError) {
      console.error("Error al iniciar sesión con Google:", loginError);
      setError("No se pudo iniciar sesión. Intenta de nuevo.");
    }
  }, []);

  const logout = useCallback(async () => {
    const { error: logoutError } = await supabase.auth.signOut();

    if (logoutError) {
      console.error("Error al cerrar sesión:", logoutError);
      setError("No se pudo cerrar sesión. Intenta de nuevo.");
      return;
    }

    setUser(null);
    setAccess(null);
    setError(null);
  }, []);

  const isGerardo = useMemo(() => access?.role === "director_creativo", [access?.role]);
  const canManageInternalPricing = useMemo(
    () => access?.canManageInternalPricing === true,
    [access?.canManageInternalPricing],
  );
  const canDeleteProjects = useMemo(
    () => access?.canDeleteProjects === true,
    [access?.canDeleteProjects],
  );
  const canControlPricingSummary = useMemo(
    () => access?.canControlPricingSummary === true,
    [access?.canControlPricingSummary],
  );
  const canManageTariffCatalog = useMemo(
    () => access?.canManageTariffCatalog === true,
    [access?.canManageTariffCatalog],
  );
  const canViewTeamHours = useMemo(
    () => access?.canViewTeamHours === true,
    [access?.canViewTeamHours],
  );
  const canCreateProjects = useMemo(
    () => access?.canCreateProjects === true,
    [access?.canCreateProjects],
  );

  return (
    <AuthContext.Provider
      value={{
        user,
        loading,
        error,
        isGerardo,
        canDeleteProjects,
        canManageInternalPricing,
        canControlPricingSummary,
        canManageTariffCatalog,
        canViewTeamHours,
        canCreateProjects,
        loginWithGoogle,
        logout,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
}

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