import { create } from "zustand";
import {
    getMe as apiGetMe,
    login as apiLogin,
    logout as apiLogout,
    register as apiRegister,
    verificarCodigo as apiVerificarCodigo,
    isAuthenticated as checkIsAuthenticated,
    clearTokens,
    enviarCodigoVerificacion,
    getStoredUser,
    registrarAuthStore,
} from "../api";

// Keys para localStorage
const USER_CONTEXT_KEY = "user_context";

// Restaurar contexto desde localStorage
const getStoredContext = () => {
  try {
    const ctx = localStorage.getItem(USER_CONTEXT_KEY);
    return ctx ? JSON.parse(ctx) : null;
  } catch {
    return null;
  }
};

const storedContext = getStoredContext();

export const useAuthStore = create((set, get) => ({
  // Estado principal
  user: getStoredUser(),
  empresa: storedContext?.empresa || null,
  suscripcion: storedContext?.suscripcion || null,
  modulos: storedContext?.modulos || [], // string[] de códigos: ['DASHBOARD','POS_RETAIL',...]
  modulosDetalle: storedContext?.modulosDetalle || [], // {codigo, descripcion, tipo}[]
  permisos: storedContext?.permisos || {}, // { MODULO_CODIGO: ['LEER','CREAR',...] }
  // Privilegios bloqueados por el plan (submódulo excluido dentro de un módulo activo).
  // Se aplican también a superAdmin: bypasea el perfil (Capa 2), NO el plan (Capa 1).
  privilegiosBloqueados: storedContext?.privilegios_bloqueados || [],
  // Contexto de rubro/sucursal (docs/plan-rubros-multi-sucursal.md del backend).
  // `sucursalDefaultId` sale de las asignaciones del usuario: es el campo que
  // el código venía leyendo como `user.sucursal_id`, que nunca existió.
  rubrosDisponibles: storedContext?.rubros_disponibles || [],
  rubroDefaultId: storedContext?.rubro_default_id || null,
  // true = puede elegir "Todos los rubros". Si el backend todavía no lo manda,
  // se asume sin restricción (comportamiento anterior).
  rubrosTodos: storedContext?.rubros_todos ?? true,
  sucursalesAsignadas: storedContext?.sucursales_asignadas || [],
  sucursalDefaultId: storedContext?.sucursal_default_id || null,
  isSuperAdmin: storedContext?.user?.is_superadmin || false,
  isAuthenticated: checkIsAuthenticated(),
  isLoading: false,
  error: null,

  // ── Cargar contexto completo desde /auth/me ──
  fetchMe: async () => {
    try {
      const data = await apiGetMe();

      // Persistir en localStorage para hidratación rápida
      localStorage.setItem(USER_CONTEXT_KEY, JSON.stringify(data));

      // Actualizar también el user básico en localStorage
      if (data.user) {
        const storedUser = getStoredUser();
        const mergedUser = {
          ...storedUser,
          ...data.user,
          empresa: data.empresa,
        };
        localStorage.setItem("user", JSON.stringify(mergedUser));
      }

      set({
        user: { ...getStoredUser(), ...data.user, empresa: data.empresa },
        empresa: data.empresa,
        suscripcion: data.suscripcion,
        modulos: data.modulos || [],
        modulosDetalle: data.modulos_detalle || [],
        permisos: data.permisos || {},
        privilegiosBloqueados: data.privilegios_bloqueados || [],
        rubrosDisponibles: data.rubros_disponibles || [],
        rubroDefaultId: data.rubro_default_id || null,
        rubrosTodos: data.rubros_todos ?? true,
        sucursalesAsignadas: data.sucursales_asignadas || [],
        sucursalDefaultId: data.sucursal_default_id || null,
        isSuperAdmin: data.user?.is_superadmin || false,
      });
      return data;
    } catch (error) {
      console.error("Error en fetchMe:", error);
      return null;
    }
  },

  // Login con usuario (RUC/username) y password
  login: async (credentials) => {
    set({ isLoading: true, error: null });
    try {
      const response = await apiLogin({
        usuario: credentials.usuario,
        password: credentials.password,
      });

      // Cargar contexto completo con /auth/me
      const meData = await apiGetMe();

      // Persistir contexto
      localStorage.setItem(USER_CONTEXT_KEY, JSON.stringify(meData));

      const fullUser = {
        ...response.user,
        ...meData.user,
        empresa: meData.empresa,
      };
      localStorage.setItem("user", JSON.stringify(fullUser));

      set({
        user: fullUser,
        empresa: meData.empresa,
        suscripcion: meData.suscripcion,
        modulos: meData.modulos || [],
        modulosDetalle: meData.modulos_detalle || [],
        permisos: meData.permisos || {},
        privilegiosBloqueados: meData.privilegios_bloqueados || [],
        rubrosDisponibles: meData.rubros_disponibles || [],
        rubroDefaultId: meData.rubro_default_id || null,
        rubrosTodos: meData.rubros_todos ?? true,
        sucursalesAsignadas: meData.sucursales_asignadas || [],
        sucursalDefaultId: meData.sucursal_default_id || null,
        isSuperAdmin: meData.user?.is_superadmin || false,
        isAuthenticated: true,
        isLoading: false,
      });
      return response;
    } catch (error) {
      const message =
        error.response?.data?.message ||
        error.message ||
        "Error al iniciar sesión";
      set({ error: message, isLoading: false });
      throw new Error(message);
    }
  },

  // Registro de empresa y usuario
  register: async (data) => {
    set({ isLoading: true, error: null });
    try {
      const response = await apiRegister(data);
      set({ isLoading: false });
      return response;
    } catch (error) {
      const message =
        error.response?.data?.message || error.message || "Error al registrar";
      set({ error: message, isLoading: false });
      throw new Error(message);
    }
  },

  // Cerrar sesión
  cerrarSesion: async ({ redirect = true } = {}) => {
    set({ isLoading: true });
    try {
      await apiLogout();
    } catch (error) {
      console.error("Error en logout:", error);
    } finally {
      clearTokens();
      localStorage.removeItem(USER_CONTEXT_KEY);
      set({
        user: null,
        empresa: null,
        suscripcion: null,
        modulos: [],
        modulosDetalle: [],
        permisos: {},
        privilegiosBloqueados: [],
        rubrosDisponibles: [],
        rubroDefaultId: null,
        rubrosTodos: true,
        sucursalesAsignadas: [],
        sucursalDefaultId: null,
        isSuperAdmin: false,
        isAuthenticated: false,
        isLoading: false,
      });
      // Navegación dura a /login: garantiza HTML fresco y evita el error
      // "Failed to fetch dynamically imported module" cuando el chunk
      // cacheado (ej: Login-<hash>.js) ya no existe tras un deploy.
      // Solo redirigir si NO estamos ya en /login para evitar loops cuando
      // el handler de auth:logout-required dispara cerrarSesion al recargar.
      if (
        redirect &&
        typeof window !== "undefined" &&
        window.location.pathname !== "/login"
      ) {
        window.location.replace("/login");
      }
    }
  },

  // Enviar código de verificación (celular o email)
  enviarCodigo: async (data) => {
    set({ isLoading: true, error: null });
    try {
      const response = await enviarCodigoVerificacion(data);
      set({ isLoading: false });
      return response;
    } catch (error) {
      const message =
        error.response?.data?.message ||
        error.message ||
        "Error al enviar código";
      set({ error: message, isLoading: false });
      throw new Error(message);
    }
  },

  // Verificar código
  verificarCodigo: async (data) => {
    set({ isLoading: true, error: null });
    try {
      const response = await apiVerificarCodigo(data);
      set({ isLoading: false });
      return response;
    } catch (error) {
      const message =
        error.response?.data?.message ||
        error.message ||
        "Error al verificar código";
      set({ error: message, isLoading: false });
      throw new Error(message);
    }
  },

  // Verificar estado de autenticación (al cargar la app)
  checkAuth: () => {
    const authenticated = checkIsAuthenticated();
    const user = getStoredUser();
    const ctx = getStoredContext();
    set({
      isAuthenticated: authenticated,
      user,
      empresa: ctx?.empresa || null,
      suscripcion: ctx?.suscripcion || null,
      modulos: ctx?.modulos || [],
      modulosDetalle: ctx?.modulos_detalle || ctx?.modulosDetalle || [],
      permisos: ctx?.permisos || {},
      privilegiosBloqueados: ctx?.privilegios_bloqueados || [],
      isSuperAdmin: ctx?.user?.is_superadmin || user?.isSuperAdmin || false,
    });
    return authenticated;
  },

  // ── Capa 1: Verificar si el módulo está en el plan de la suscripción ──
  // Holdings/resellers bypasean el plan (no tienen suscripción propia)
  hasModulePlan: (moduloCodigo) => {
    const { modulos, empresa } = get();
    if (empresa?.type === "holding" || empresa?.type === "reseller")
      return true;
    return modulos.includes(moduloCodigo);
  },

  // ── Capa 1 + Capa 2: Módulo en plan Y usuario tiene al menos un permiso ──
  // Holdings/resellers bypasean capa 1 (no tienen suscripción propia)
  // SuperAdmin bypasea capa 2 (permisos usuario)
  hasModule: (moduloCodigo) => {
    const { modulos, permisos, isSuperAdmin, empresa } = get();
    const isHoldingOrReseller =
      empresa?.type === "holding" || empresa?.type === "reseller";
    // Capa 1: módulo debe estar en el plan (holdings/resellers bypasean)
    if (!isHoldingOrReseller && !modulos.includes(moduloCodigo)) return false;
    // Capa 2: superAdmin bypasea solo permisos de usuario, NO el plan
    if (isSuperAdmin) return true;
    // Usuarios normales: deben tener al menos un privilegio asignado
    const privs = permisos[moduloCodigo];
    return Array.isArray(privs) && privs.length > 0;
  },

  // ── Verificar si tiene permiso específico sobre un módulo ──
  // Uso: hasPermission('PRODUCTOS', 'CREAR')
  //      hasPermission('PRODUCTOS') → true si tiene al menos un privilegio
  // Holdings/resellers bypasean capa 1 (plan). SuperAdmin bypasea capa 2 (permisos).
  hasPermission: (moduloCodigo, privilegioCodigo = null) => {
    const { modulos, permisos, isSuperAdmin, empresa, privilegiosBloqueados } = get();
    const isHoldingOrReseller =
      empresa?.type === "holding" || empresa?.type === "reseller";
    // Capa 1 (módulo): el módulo debe estar en el plan (holdings/resellers bypasean)
    if (!isHoldingOrReseller && !modulos.includes(moduloCodigo)) return false;
    // Capa 1 (submódulo): si el privilegio pertenece a un submódulo EXCLUIDO del plan,
    // se bloquea aunque el módulo esté activo. Aplica también a superAdmin, que bypasea
    // el perfil (Capa 2) pero NO el plan. Holdings/resellers bypasean.
    if (
      !isHoldingOrReseller &&
      privilegioCodigo &&
      privilegiosBloqueados.includes(privilegioCodigo)
    )
      return false;
    // Capa 2: superAdmin bypasea solo permisos de usuario, NO el plan
    if (isSuperAdmin) return true;
    // Usuarios normales (incluidos los de holdings): verificar privilegio específico
    const privs = permisos[moduloCodigo];
    if (!privs || privs.length === 0) return false;
    if (privilegioCodigo === null) return true;
    return privs.includes(privilegioCodigo);
  },

  // Actualizar empresa activa del usuario (después de switch-empresa)
  updateEmpresaActiva: async (empresaId, empresaData) => {
    const currentUser = getStoredUser();
    if (currentUser) {
      const updatedUser = {
        ...currentUser,
        empresa_id: empresaId,
        empresa: empresaData || currentUser.empresa,
      };
      localStorage.setItem("user", JSON.stringify(updatedUser));
      set({ user: updatedUser, empresa: empresaData || currentUser.empresa });

      // Recargar contexto completo para la nueva empresa
      await get().fetchMe();
    }
  },

  // Limpiar errores
  clearError: () => set({ error: null }),

  // Refrescar el objeto empresa en memoria sin hacer fetchMe completo.
  // Útil cuando cambia un flag concreto desde una pantalla de config
  // y queremos que las UIs reactivas (ej. checks de sifen_activo) lo
  // tomen al toque sin esperar al próximo reload.
  setEmpresa: (empresaData) => {
    const currentUser = getStoredUser();
    if (currentUser) {
      const updatedUser = { ...currentUser, empresa: empresaData };
      localStorage.setItem("user", JSON.stringify(updatedUser));
      set({ user: updatedUser, empresa: empresaData });
    }
  },
}));

// El interceptor de axios necesita los rubros disponibles del usuario para
// decidir si manda `x-rubro-id`; no puede importar este store (ciclo).
registrarAuthStore(useAuthStore);
