import React, { createContext, useState, useContext, type ReactNode, useEffect, useCallback } from 'react';
import { jwtDecode } from 'jwt-decode';
import { getAlertas, marcarAlertaLeida, marcarGrupoComoLeido, type AlertaGenericaDto } from '../services/Anomalia/alertaService';

export interface UserContextData {
  userId: number;
  username: string;
  nombreCompleto: string;
  esSuperAdmin: boolean;
  debeCambiarClave: boolean;
  perfil: string;
  idPerfil: number;
  permissions: string[];
}

interface DecodedJwtPayload {
  sub: string;
  name: string;
  given_name?: string;
  family_name?: string;
  role: string | string[];
  perfil: string;
  idPerfil: string;
  debeCambiarClave: string;
  permission?: string | string[];
  [key: string]: any;
}

interface AuthContextType {
  isAuthenticated: boolean;
  user: UserContextData | null;
  token: string | null;
  isLoading: boolean;
  alertas: AlertaGenericaDto[];
  showForcedPasswordChangeModal: boolean;
  isPasswordChangeForced: boolean;

  marcarAlertaComoLeida: (idAlerta: number) => Promise<void>;
  marcarGrupoDeAlertasLeido: (tipoAlerta: string, idEntidad: number) => Promise<void>;

  setShowForcedPasswordChangeModal: (show: boolean) => void;
  passwordChangeCompleted: () => void;
  login: (apiLoginResponse: any) => void; // DTO no definido aquí, usamos any
  logout: () => void;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);

export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
  const [user, setUser] = useState<UserContextData | null>(null);
  const [token, setToken] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState<boolean>(true);
  const [showForcedPasswordChangeModal, setShowForcedPasswordChangeModal] = useState<boolean>(false);
  const [isPasswordChangeForced, setIsPasswordChangeForced] = useState<boolean>(false);
  const [alertas, setAlertas] = useState<AlertaGenericaDto[]>([]);

  const fetchAlertas = useCallback(async (currentUser: UserContextData | null) => {
    if (currentUser && (currentUser.esSuperAdmin || currentUser.permissions.includes('AL001'))) {
      try {
        const data = await getAlertas();
        setAlertas(data || []);
      } catch (error) {
        console.error("Error al obtener alertas en AuthContext:", error);
        setAlertas([]);
      }
    } else {
      setAlertas([]);
    }
  }, []);

  const marcarAlertaComoLeida = async (idAlerta: number) => {
    try {
      await marcarAlertaLeida(idAlerta);
      await fetchAlertas(user); // Refresca el estado global
    } catch (error) {
      console.error("Error al marcar alerta como leída:", error);
    }
  };

  const marcarGrupoDeAlertasLeido = async (tipoAlerta: string, idEntidad: number) => {
    try {
      await marcarGrupoComoLeido({ tipoAlerta, idEntidad });
      await fetchAlertas(user); // Refresca el estado global
    } catch (error) {
      console.error(`Error al marcar grupo ${tipoAlerta}/${idEntidad} como leído:`, error);
    }
  };

  const logout = useCallback(() => {
    localStorage.removeItem('authToken');
    setToken(null);
    setUser(null);
    setIsAuthenticated(false);
    setShowForcedPasswordChangeModal(false);
    setIsPasswordChangeForced(false);
    setAlertas([]);
  }, []);

  const processTokenAndSetUser = useCallback((jwtToken: string) => {
    try {
      const decodedToken = jwtDecode<DecodedJwtPayload>(jwtToken);
      const currentTime = Date.now() / 1000;
      if (decodedToken.exp && decodedToken.exp < currentTime) {
        logout(); return;
      }
      const userForContext: UserContextData = {
        userId: parseInt(decodedToken.sub, 10),
        username: decodedToken.name,
        nombreCompleto: `${decodedToken.given_name || ''} ${decodedToken.family_name || ''}`.trim(),
        esSuperAdmin: decodedToken.role === "SuperAdmin" || (Array.isArray(decodedToken.role) && decodedToken.role.includes("SuperAdmin")),
        debeCambiarClave: decodedToken.debeCambiarClave?.toLowerCase() === 'true',
        idPerfil: decodedToken.idPerfil ? parseInt(decodedToken.idPerfil, 10) : 0,
        permissions: Array.isArray(decodedToken.permission) ? decodedToken.permission : (decodedToken.permission ? [decodedToken.permission] : []),
        perfil: decodedToken.perfil || 'Usuario'
      };
      setToken(jwtToken);
      setUser(userForContext);
      setIsAuthenticated(true);
      localStorage.setItem('authToken', jwtToken);

      if (userForContext.debeCambiarClave) {
        setShowForcedPasswordChangeModal(true);
        setIsPasswordChangeForced(true);
      }
    } catch (error) {
      console.error("Error al decodificar token:", error);
      logout();
    }
  }, [logout]);

  useEffect(() => {
    setIsLoading(true);
    const storedToken = localStorage.getItem('authToken');
    if (storedToken) {
      processTokenAndSetUser(storedToken);
    }
    setIsLoading(false);
  }, [processTokenAndSetUser]);

  useEffect(() => {
    if (user && isAuthenticated) {
        fetchAlertas(user);
        const intervalId = setInterval(() => fetchAlertas(user), 300000); // Refresca cada 5 mins
        return () => clearInterval(intervalId);
    }
  }, [user, isAuthenticated, fetchAlertas]);

  const login = (apiLoginResponse: any) => {
    processTokenAndSetUser(apiLoginResponse.token);
  };

  const passwordChangeCompleted = () => {
    setShowForcedPasswordChangeModal(false);
    setIsPasswordChangeForced(false);
    // Importante: Si el cambio de clave afecta el claim "debeCambiarClave" en el token,
    // idealmente el backend debería devolver un *nuevo token* después del cambio de clave.
    // Si no lo hace, el token actual aún dirá que debe cambiar clave.
    // Una solución simple es actualizar el estado local del usuario:
    if (user) {
      const updatedUser = { ...user, debeCambiarClave: false };
      setUser(updatedUser);
      localStorage.setItem('authUser', JSON.stringify(updatedUser));
    }
  };

  return (
    <AuthContext.Provider value={{
      isAuthenticated, user, token, isLoading,
      showForcedPasswordChangeModal, isPasswordChangeForced,
      alertas, marcarAlertaComoLeida, marcarGrupoDeAlertasLeido,
      setShowForcedPasswordChangeModal, passwordChangeCompleted,
      login, logout
    }}>
      {children}
    </AuthContext.Provider>
  );
};

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