/* MIRAI — Capa de datos del dashboard (mock vs. backend en vivo)
 *
 * useDashboardData(user, filters) devuelve SIEMPRE la misma forma, de modo que
 * los componentes del dashboard no cambian:
 *   { isLive, loading, error, empty, missing, lastUpdated, refresh(),
 *     metrics, series, results, channels, rows, zones, zonesFull,
 *     unresolved, unresolvedFull, intentions, recent, peakHours }
 *
 * - Cuentas mock (p.ej. "fran"): usa las funciones dashGetX() existentes.
 * - Cuentas en vivo (p.ej. "deleo"): pide /api/metrics con el token de sesión,
 *   refresca automáticamente cada 10 minutos y permite refresco manual.
 */

// Cuentas que consumen datos reales del backend.
const MIRAI_LIVE_USERS = new Set(["deleo"]);
const MIRAI_REFRESH_MS = 2 * 60 * 1000; // 2 minutos

// Quita acentos/diacríticos y pasa a minúsculas (ej. "Pérez" -> "perez") para
// que la búsqueda no dependa de tildes.
function miraiNormalizeText(s) {
  return String(s || "").normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
}

// Búsqueda usada por el Tablero ("nombre o teléfono") y el Inbox ("nombre o
// @handle"). Mejora el simple .includes() de antes:
//  - ignora acentos/mayúsculas ("perez" encuentra "Pérez")
//  - separa la búsqueda en palabras y no importa el orden ("gonzalez martin"
//    encuentra a "Martín González")
//  - para el teléfono compara solo dígitos, así el formato no importa
//    ("11 2866-1164" encuentra a "+54 9 11 2866 1164")
//  - "phone" también puede ser un @handle de Instagram (texto, no dígitos):
//    se busca como texto igual que el nombre.
function miraiMatchesSearch(query, name, phone) {
  const raw = String(query || "").trim();
  if (!raw) return true;
  const words = miraiNormalizeText(raw).split(/\s+/).filter(Boolean);
  const haystack = miraiNormalizeText(`${name || ""} ${phone || ""}`);
  const textMatch = words.length > 0 && words.every((w) => haystack.includes(w));
  const queryDigits = raw.replace(/\D/g, "");
  const phoneDigits = String(phone || "").replace(/\D/g, "");
  const phoneMatch = queryDigits.length >= 2 && phoneDigits.includes(queryDigits);
  return textMatch || phoneMatch;
}

// Formato fijo del diagnóstico (Inbox de WhatsApp, Tablero y "Últimas
// consultas"): mismo texto para lo que se muestra en pantalla y para lo que
// se copia al portapapeles con "Copiar diagnóstico".
function miraiFormatDiagnosis({ name, operator, phone, intent, summary }) {
  return [
    `Diagnostico de "${name || "—"}"`,
    `Recibido por: "${operator || "Sin asignar"}"`,
    "",
    `Numero: "${phone || "—"}"`,
    `Intencion: "${intent || "—"}"`,
    `Resumen de conversacion: "${summary || "—"}"`,
  ].join("\n");
}

// Entornos de Supabase entre los que se puede alternar en el dashboard.
// "prod" primero: es el default si no hay nada guardado (o si lo guardado
// quedó obsoleto), y ahí vive la data real del cliente.
const MIRAI_ENVIRONMENTS = [
  { key: "prod", label: "Producción" },
  { key: "tester", label: "Tester" },
];
const MIRAI_ENV_KEY = "mirai_env";

// Cuentas con el switcher tester/producción deshabilitado a pedido del
// cliente: siempre ven el entorno de producción, sin selector en ningún lado
// del dashboard (y sin importar lo que haya quedado guardado en localStorage
// de antes de este cambio).
const MIRAI_ENV_SWITCH_DISABLED = new Set(["deleo"]);

// Hook: entorno elegido (tester/producción), persistido en localStorage —
// mismo criterio que useAuth (estado levantado arriba, sin Context).
function useMiraiEnv(user) {
  const isLive = MIRAI_LIVE_USERS.has((user || "").toLowerCase());
  const showEnvSwitch = isLive && !MIRAI_ENV_SWITCH_DISABLED.has((user || "").toLowerCase());
  const [env, setEnv] = React.useState(() => {
    if (!showEnvSwitch) return MIRAI_ENVIRONMENTS[0].key;
    try {
      const stored = localStorage.getItem(MIRAI_ENV_KEY);
      // Si lo guardado ya no es un entorno válido (p.ej. quedó de una versión
      // vieja), lo ignoramos en vez de mandarlo al backend y caer a un default
      // silencioso — así nadie queda "trabado" viendo el entorno equivocado.
      if (stored && MIRAI_ENVIRONMENTS.some((e) => e.key === stored)) return stored;
    } catch (e) {}
    return MIRAI_ENVIRONMENTS[0].key;
  });
  const setEnvPersist = React.useCallback((next) => {
    setEnv(next);
    try { localStorage.setItem(MIRAI_ENV_KEY, next); } catch (e) {}
  }, []);
  return { env, setEnv: setEnvPersist, showEnvSwitch };
}

function useDashboardData(user, filters, env) {
  const isLive = MIRAI_LIVE_USERS.has((user || "").toLowerCase());
  const [live, setLive] = React.useState(null);
  const [loading, setLoading] = React.useState(isLive);
  const [error, setError] = React.useState(null);
  const [lastUpdated, setLastUpdated] = React.useState(null);

  const period = filters.period;
  const channel = filters.channel || "all";

  // Carga (o recarga) los datos reales del backend. force=true (botón
  // "Actualizar") saltea la caché de 2 min del servidor para reflejar al
  // instante cambios hechos directo en Supabase (ej. un lead borrado a mano);
  // el refresco automático de fondo no lo manda.
  const load = React.useCallback((force) => {
    if (!isLive) { setLastUpdated(new Date()); return Promise.resolve(); }
    const token = (typeof miraiSessionToken === "function") ? miraiSessionToken() : null;
    setLoading(true);
    const forceParam = force ? "&force=1" : "";
    return fetch(`/api/metrics?period=${encodeURIComponent(period)}&channel=${encodeURIComponent(channel)}&env=${encodeURIComponent(env || "")}${forceParam}`, {
      headers: token ? { Authorization: `Bearer ${token}` } : {},
    })
      .then((r) => {
        if (r.status === 204) return null;          // cuenta sin datos en Supabase
        if (!r.ok) throw new Error("HTTP " + r.status);
        return r.json();
      })
      .then((d) => { setLive(d); setError(null); setLastUpdated(new Date()); })
      .catch((e) => { setError(e); })
      .finally(() => { setLoading(false); });
  }, [isLive, period, channel, env]);

  React.useEffect(() => {
    let cancelled = false;
    const run = () => { if (!cancelled) load(); };
    run();
    const iv = setInterval(run, MIRAI_REFRESH_MS); // refresco automático cada 2 min
    return () => { cancelled = true; clearInterval(iv); };
  }, [load]);

  // Refresco manual (botón "Actualizar"): siempre fuerza datos frescos.
  const forceRefresh = React.useCallback(() => load(true), [load]);

  if (!isLive) {
    return {
      isLive: false, loading: false, error: null, empty: false, missing: [],
      lastUpdated, refresh: forceRefresh,
      metrics: dashGetMetrics(filters),
      series: dashGetSeries(filters),
      results: dashGetResults(filters),
      channels: dashGetChannels(filters),
      rows: dashGetConsultations(filters),
      zones: dashGetZones(filters),
      zonesFull: DASH_ZONES_FULL,
      unresolved: dashGetUnresolved(filters),
      unresolvedFull: DASH_UNRESOLVED,
      intentions: [],
      recent: [],
      peakHours: [],
    };
  }

  const d = live || {};
  return {
    isLive: true,
    loading,
    error,
    empty: d.empty === true,
    missing: d.missing || [],
    lastUpdated,
    refresh: forceRefresh,
    metrics: d.metrics || [],
    series: d.series || { labels: [], consultas: [], leads: [] },
    results: d.results || [],
    channels: d.channels || [],
    rows: d.consultations || [],
    zones: d.zones || [],
    zonesFull: d.zonesFull || [],
    unresolved: d.unresolved || [],
    unresolvedFull: d.unresolved || [],
    intentions: d.intentions || [],
    recent: d.recent || [],
    peakHours: d.peakHours || [],
  };
}

// Formatea la hora de última actualización de forma discreta (HH:MM).
function miraiFmtTime(date) {
  if (!date) return "";
  try {
    return date.toLocaleTimeString("es-AR", { hour: "2-digit", minute: "2-digit" });
  } catch (e) { return ""; }
}

// Hook: lista de leads activos desde /dashboard/chats (solo usuarios en vivo).
function useInboxChats(user, env) {
  const isLive = MIRAI_LIVE_USERS.has((user || "").toLowerCase());
  const [chats, setChats] = React.useState([]);
  const [loading, setLoading] = React.useState(isLive);
  const [error, setError] = React.useState(null);

  // force=true (botón "Actualizar") saltea la caché de 2 min del servidor —
  // ver el mismo criterio en useDashboardData más arriba.
  const load = React.useCallback((force) => {
    if (!isLive) return Promise.resolve();
    const token = (typeof miraiSessionToken === "function") ? miraiSessionToken() : null;
    setLoading(true);
    const forceParam = force ? "&force=1" : "";
    return fetch(`/dashboard/chats?env=${encodeURIComponent(env || "")}${forceParam}`, {
      headers: token ? { Authorization: `Bearer ${token}` } : {},
    })
      .then((r) => { if (!r.ok) throw new Error("HTTP " + r.status); return r.json(); })
      .then((d) => { setChats(d.chats || []); setError(null); })
      .catch((e) => { setError(e); })
      .finally(() => { setLoading(false); });
  }, [isLive, env]);

  React.useEffect(() => {
    load();
    if (!isLive) return;
    const iv = setInterval(load, MIRAI_REFRESH_MS);
    return () => clearInterval(iv);
  }, [load, isLive]);

  const forceRefresh = React.useCallback(() => load(true), [load]);

  return { chats, loading, error, refresh: forceRefresh, isLive };
}

// Hook: mensajes de un chat desde /dashboard/chats/:phone/messages (solo usuarios en vivo).
function useInboxMessages(user, phone, env) {
  const isLive = MIRAI_LIVE_USERS.has((user || "").toLowerCase());
  const [messages, setMessages] = React.useState([]);
  const [loading, setLoading] = React.useState(false);

  React.useEffect(() => {
    if (!isLive || !phone) { setMessages([]); return; }
    const token = (typeof miraiSessionToken === "function") ? miraiSessionToken() : null;
    let cancelled = false;
    setLoading(true);
    fetch(`/dashboard/chats/${encodeURIComponent(phone)}/messages?env=${encodeURIComponent(env || "")}`, {
      headers: token ? { Authorization: `Bearer ${token}` } : {},
    })
      .then((r) => { if (!r.ok) throw new Error("HTTP " + r.status); return r.json(); })
      .then((d) => { if (!cancelled) setMessages(d.messages || []); })
      .catch(() => { if (!cancelled) setMessages([]); })
      .finally(() => { if (!cancelled) setLoading(false); });
    return () => { cancelled = true; };
  }, [isLive, phone, env]);

  return { messages, loading };
}

// Guarda a quién se derivó un lead (PATCH /dashboard/chats/:phone/assign).
// derivedTo === "" desasigna. Sólo tiene sentido para cuentas en vivo.
async function mirai_assignDerivedTo(phone, derivedTo, env) {
  const token = (typeof miraiSessionToken === "function") ? miraiSessionToken() : null;
  const res = await fetch(`/dashboard/chats/${encodeURIComponent(phone)}/assign?env=${encodeURIComponent(env || "")}`, {
    method: "PATCH",
    headers: { "Content-Type": "application/json", ...(token ? { Authorization: `Bearer ${token}` } : {}) },
    body: JSON.stringify({ derivedTo }),
  });
  if (!res.ok) throw new Error("HTTP " + res.status);
  return res.json();
}

Object.assign(window, { useDashboardData, useInboxChats, useInboxMessages, useMiraiEnv, MIRAI_LIVE_USERS, MIRAI_ENVIRONMENTS, miraiFmtTime, mirai_assignDerivedTo, miraiMatchesSearch, miraiFormatDiagnosis });
