// View components — one per tab

// =========================
// OVERVIEW
// =========================
function OverviewView({ data, onCall, onSelectPatient, onGoTab }) {
  const patients = data.patients || [];
  const interactions = data.interactions || [];
  const escalations = data.escalations || [];

  const totalPatients = patients.length;
  const waiting = patients.filter((p) => p.status === "waiting").length;
  const high = patients.filter((p) => p.priority === "alta").length;
  const overdue = patients.filter(isOverdue);
  const activeEscalations = escalations.filter((e) => e.status === "pending");

  // Activity feed: merge interactions + escalations sorted desc
  const feed = React.useMemo(() => {
    const items = [
      ...interactions.map((i) => ({ kind: "interaction", date: i.date, data: i })),
      ...escalations.map((e) => ({ kind: "escalation", date: e.date, data: e })),
    ];
    return [...items].sort((a, b) => new Date(b.date) - new Date(a.date)).slice(0, 12);
  }, [interactions, escalations]);

  const patientById = (id) => patients.find((p) => p.id === id);

  return (
    <div className="flex flex-col gap-6">
      <SectionHeader
        title="Panel general"
        subtitle={`${getMadridGreeting()}. Resumen operativo de hoy.`}
        action={
          <div className="flex items-center gap-2 text-xs text-ink-400 font-mono">
            <span className="w-1.5 h-1.5 rounded-full bg-emerald-400 pulse-dot"></span>
            Clara activa · sincronizando
          </div>
        }
      />

      {/* KPIs */}
      <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-3">
        <KpiCard label="Pacientes" value={totalPatients} sub="activos en cartera" icon={<I.Users size={14} />} />
        <KpiCard label="En espera" value={waiting} sub="aguardando equipo" icon={<I.Clock size={14} />} />
        <KpiCard label="Prioridad alta" value={high} sub="seguimiento estrecho" tone="rose" icon={<I.AlertTriangle size={14} />} />
        <KpiCard label="Sobrepasan frecuencia" value={overdue.length} sub="contactar hoy" tone="amber" icon={<I.PhoneOff size={14} />} />
        <KpiCard label="Interacciones" value={interactions.length} sub="totales registradas" icon={<I.Activity size={14} />} />
      </div>

      <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
        {/* Activity feed */}
        <div className="card rounded-xl p-5 lg:col-span-3 flex flex-col">
          <div className="flex items-center justify-between mb-4">
            <div>
              <h2 className="text-sm font-semibold text-ink-100">Actividad reciente</h2>
              <p className="text-xs text-ink-400 mt-0.5">Llamadas y mensajes</p>
            </div>
            <button onClick={() => onGoTab("interactions")} className="text-xs text-sky-300 hover:text-sky-200 inline-flex items-center gap-1">
              Ver todo <I.ArrowRight size={12} />
            </button>
          </div>
          {(() => {
            if (feed.length === 0) return <Empty>Sin actividad</Empty>;

            const now = new Date();
            const todayStr = now.toISOString().split("T")[0];
            const yesterday = new Date(now); yesterday.setDate(yesterday.getDate() - 1);
            const yesterdayStr = yesterday.toISOString().split("T")[0];

            // Group by day → hour
            const dayGroups = {};
            for (const it of feed) {
              const d = it.date.split("T")[0];
              const label = d === todayStr ? "Hoy" : d === yesterdayStr ? "Ayer" : fmtDate(it.date, { year: true });
              if (!dayGroups[label]) dayGroups[label] = {};
              const h = `${String(new Date(it.date).getHours()).padStart(2, "0")}:00`;
              if (!dayGroups[label][h]) dayGroups[label][h] = [];
              dayGroups[label][h].push(it);
            }

            return Object.entries(dayGroups).map(([dayLabel, hours]) => (
              <div key={dayLabel} className="mb-3">
                <div className="text-[10px] uppercase tracking-wider text-ink-500 font-semibold mb-2">{dayLabel}</div>
                {Object.entries(hours).sort((a, b) => b[0].localeCompare(a[0])).map(([hour, items]) => (
                  <div key={hour} className="mb-2">
                    <div className="text-[10px] font-mono text-ink-600 mb-1 flex items-center gap-1">
                      <I.Clock size={9} /> {hour}
                    </div>
                    <ul className="flex flex-col">
                      {items.map((it, idx) => {
                        const p = patientById(it.data.patientId);
                        const isLast = idx === items.length - 1;
                        if (it.kind === "interaction") {
                          const m = channelMeta(it.data.channel);
                          const Icn = I[m.icon];
                          const dirIcon = it.data.direction === "outbound" ? <I.ArrowUpRight size={12} /> : <I.ArrowDownLeft size={12} />;
                          const time = new Date(it.data.date);
                          const timeStr = `${String(time.getHours()).padStart(2, "0")}:${String(time.getMinutes()).padStart(2, "0")}`;
                          return (
                            <li key={it.data.id} className="relative pl-9 pb-3">
                              {!isLast && <span className="absolute left-3 top-7 bottom-0 w-px bg-white/8"></span>}
                              <span className={`absolute left-0 top-0.5 w-6 h-6 rounded-md ${m.bg} ${m.color} inline-flex items-center justify-center`}>
                                <Icn size={12} />
                              </span>
                              <div className="flex items-baseline justify-between gap-3">
                                <button onClick={() => p && onSelectPatient(p)} className="text-sm text-ink-100 hover:text-sky-300 text-left font-medium truncate">
                                  {p ? p.name : "Paciente"}
                                </button>
                                <span className="text-[11px] text-ink-500 font-mono whitespace-nowrap">{timeStr}</span>
                              </div>
                              <div className="text-xs text-ink-400 flex items-center gap-2 mt-0.5">
                                <span className="inline-flex items-center gap-1">{dirIcon} {it.data.direction === "outbound" ? "Saliente" : "Entrante"}</span>
                                <span className="text-ink-600">·</span>
                                <span>{channelMeta(it.data.channel).label}</span>
                                <span className="text-ink-600">·</span>
                                <span>{outcomeLabel(it.data.outcome)}</span>
                              </div>
                            </li>
                          );
                        } else {
                          return (
                            <li key={it.data.id} className="relative pl-9 pb-3">
                              {!isLast && <span className="absolute left-3 top-7 bottom-0 w-px bg-white/8"></span>}
                              <span className="absolute left-0 top-0.5 w-6 h-6 rounded-md bg-amber-500/10 text-amber-300 inline-flex items-center justify-center">
                                <I.AlertTriangle size={12} />
                              </span>
                              <div className="flex items-baseline justify-between gap-3">
                                <div className="flex items-center gap-2">
                                  <button onClick={() => p && onSelectPatient(p)} className="text-sm text-ink-100 hover:text-sky-300 text-left font-medium">
                                    {p ? p.name : "Paciente"}
                                  </button>
                                  <UrgencyBadge urgency={it.data.urgency} />
                                </div>
                                <span className="text-[11px] text-ink-500 font-mono whitespace-nowrap">{fmtDate(it.data.date, { relative: true })}</span>
                              </div>
                              <div className="text-xs text-ink-400 mt-0.5 line-clamp-1">Escalación → {it.data.assignedTo}: {it.data.reason}</div>
                            </li>
                          );
                        }
                      })}
                    </ul>
                  </div>
                ))}
              </div>
            ));
          })()}
        </div>

      </div>
    </div>
  );
}

// =========================
// PATIENTS
// =========================
function PatientsView({ data, onCall, onSelectPatient, onAddNew, onDeletePatient }) {
  const [query, setQuery] = React.useState("");
  const [priority, setPriority] = React.useState("all");
  const [region, setRegion] = React.useState("all");
  const patients = data.patients || [];

  const filtered = React.useMemo(() => {
    const q = query.toLowerCase().trim();
    return patients.filter((p) => {
      if (priority !== "all" && p.priority !== priority) return false;
      if (region !== "all" && p.region !== region) return false;
      if (!q) return true;
      return (
        p.name.toLowerCase().includes(q) ||
        p.id.toLowerCase().includes(q) ||
        p.phone.toLowerCase().includes(q) ||
        p.equipmentType.toLowerCase().includes(q)
      );
    });
  }, [patients, query, priority, region]);

  const regions = Array.from(new Set(patients.map((p) => p.region))).sort();

  return (
    <div className="flex flex-col gap-5">
      <SectionHeader
        title="Pacientes"
        subtitle={`${patients.length} en cartera · ${filtered.length} mostrados`}
        action={
          <Btn tone="primary" icon={<I.Plus size={14} />} onClick={onAddNew}>Nuevo paciente</Btn>
        }
      />

      <div className="flex flex-wrap items-center gap-2">
        <div className="relative flex-1 min-w-[260px]">
          <I.Search size={14} className="absolute left-3 top-1/2 -translate-y-1/2 text-ink-500" />
          <input
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            placeholder="Buscar por nombre, ID, teléfono o equipo…"
            className="w-full bg-ink-900 border border-white/10 rounded-lg pl-9 pr-3 py-2 text-sm text-ink-100 placeholder-ink-500 ring-focus"
          />
        </div>
        <div className="inline-flex rounded-lg border border-white/10 bg-ink-900 p-0.5">
          {[
            { id: "all", label: "Todas" },
            { id: "alta", label: "Alta" },
            { id: "media", label: "Media" },
            { id: "baja", label: "Baja" },
          ].map((opt) => (
            <button
              key={opt.id}
              onClick={() => setPriority(opt.id)}
              className={`px-3 py-1.5 text-xs rounded-md transition-colors ${
                priority === opt.id ? "bg-white/10 text-ink-100" : "text-ink-400 hover:text-ink-200"
              }`}
            >
              {opt.label}
            </button>
          ))}
        </div>
        <Select value={region} onChange={(e) => setRegion(e.target.value)} className="w-44">
          <option value="all">Todas las zonas</option>
          {regions.map((r) => <option key={r} value={r}>{r}</option>)}
        </Select>
      </div>

      <div className="card rounded-xl overflow-hidden">
        <div className="overflow-x-auto">
          <table className="w-full text-sm">
            <thead>
              <tr className="text-left text-[11px] uppercase tracking-wider text-ink-500 border-b border-white/5 bg-white/2">
                <th className="px-4 py-3 font-medium">Paciente</th>
                <th className="px-4 py-3 font-medium">Equipo</th>
                <th className="px-4 py-3 font-medium">Prioridad</th>
                <th className="px-4 py-3 font-medium">Espera</th>
                <th className="px-4 py-3 font-medium">Último contacto</th>
                <th className="px-4 py-3 font-medium">Zona</th>
                <th className="px-4 py-3 font-medium text-right">Acciones</th>
              </tr>
            </thead>
            <tbody>
              {filtered.map((p) => {
                const overdue = isOverdue(p);
                const m = channelMeta(p.contactPreference);
                const Icn = I[m.icon];
                return (
                  <tr
                    key={p.id}
                    onClick={() => onSelectPatient(p)}
                    className="border-b border-white/5 last:border-0 hover:bg-white/3 cursor-pointer transition-colors"
                  >
                    <td className="px-4 py-3">
                      <div className="flex flex-col">
                        <span className="text-ink-100 font-medium">{p.name}</span>
                        <span className="text-[11px] text-ink-500 font-mono mt-0.5 flex items-center gap-2">
                          {p.id}
                          <span className="text-ink-600">·</span>
                          <span>{p.phone}</span>
                          <span className={`inline-flex items-center justify-center w-4 h-4 rounded ${m.bg} ${m.color}`} title={m.label}>
                            <Icn size={10} />
                          </span>
                        </span>
                      </div>
                    </td>
                    <td className="px-4 py-3">
                      <span className="text-ink-200">{p.equipmentType}</span>
                    </td>
                    <td className="px-4 py-3">
                      <PriorityBadge priority={p.priority} />
                    </td>
                    <td className="px-4 py-3">
                      <span className="font-mono text-xs text-ink-300">{daysWaiting(p)} d</span>
                    </td>
                    <td className="px-4 py-3">
                      <div className="flex items-center gap-2">
                        <span className="font-mono text-xs text-ink-300">
                          {daysSinceContact(p) != null ? `${daysSinceContact(p)} d` : "—"}
                        </span>
                        {overdue && (
                          <span className="inline-flex items-center gap-1 text-[10px] text-rose-300 bg-rose-500/10 px-1.5 py-0.5 rounded ring-1 ring-rose-500/30">
                            <I.AlertTriangle size={10} /> {daysSinceContact(p) - p.contactFrequencyDays}d sobre
                          </span>
                        )}
                      </div>
                    </td>
                    <td className="px-4 py-3">
                      <span className="inline-flex items-center gap-1 text-xs text-ink-400">
                        <I.MapPin size={12} /> {p.region}
                      </span>
                    </td>
                    <td className="px-4 py-3">
                      <div className="flex justify-end gap-1">
                        <CallButton patient={p} onCall={onCall} />
                        <button
                          onClick={(e) => { e.stopPropagation(); onSelectPatient(p); }}
                          className="text-xs text-ink-400 hover:text-ink-100 px-2.5 py-1.5 rounded-md hover:bg-white/5 transition-colors"
                        >
                          Ver
                        </button>
                      </div>
                    </td>
                  </tr>
                );
              })}
              {filtered.length === 0 && (
                <tr><td colSpan={7}><Empty>Sin resultados</Empty></td></tr>
              )}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

// =========================
// INTERACTIONS
// =========================
function InteractionsView({ data, onSelectPatient }) {
  const [patientFilter, setPatientFilter] = React.useState("all");
  const [channelFilter, setChannelFilter] = React.useState("all");
  const [modalId, setModalId] = React.useState(null);

  const interactions = data.interactions || [];
  const sorted = React.useMemo(() =>
    [...interactions].sort((a, b) => new Date(b.date) - new Date(a.date)),
    [interactions]
  );

  const filtered = sorted.filter((i) => {
    if (patientFilter !== "all" && i.patientId !== patientFilter) return false;
    if (channelFilter !== "all" && i.channel !== channelFilter) return false;
    return true;
  });

  const patientById = (id) => (data.patients || []).find((p) => p.id === id);

  // Group by day
  const grouped = React.useMemo(() => {
    const now = new Date();
    const todayStr = now.toISOString().split("T")[0];
    const yesterday = new Date(now); yesterday.setDate(yesterday.getDate() - 1);
    const yesterdayStr = yesterday.toISOString().split("T")[0];
    const weekAgo = new Date(now); weekAgo.setDate(weekAgo.getDate() - 7);

    const groups = {};
    for (const i of filtered) {
      const d = i.date.split("T")[0];
      let label;
      if (d === todayStr) label = "Hoy";
      else if (d === yesterdayStr) label = "Ayer";
      else if (new Date(d) >= weekAgo) label = "Esta semana";
      else label = "Más antiguas";
      if (!groups[label]) groups[label] = [];
      groups[label].push(i);
    }
    return groups;
  }, [filtered]);

  const groupOrder = ["Hoy", "Ayer", "Esta semana", "Más antiguas"];
  const groupIcons = {
    "Hoy": <I.Zap size={13} />,
    "Ayer": <I.Clock size={13} />,
    "Esta semana": <I.Calendar size={13} />,
    "Más antiguas": <I.Archive size={13} />,
  };

  // Modal interaction
  const modalInteraction = modalId ? filtered.find((i) => i.id === modalId) : null;
  const modalPatient = modalInteraction ? patientById(modalInteraction.patientId) : null;
  const modalParsed = modalInteraction ? parseTranscript(modalInteraction.summary) : null;

  return (
    <div className="flex flex-col gap-5">
      <SectionHeader
        title="Llamadas"
        subtitle={`${interactions.length} contactos registrados`}
      />

      <div className="flex flex-wrap items-center gap-2">
        <Select value={patientFilter} onChange={(e) => setPatientFilter(e.target.value)} className="w-64">
          <option value="all">Todos los pacientes</option>
          {(data.patients || []).map((p) => <option key={p.id} value={p.id}>{p.name}</option>)}
        </Select>
        <div className="inline-flex rounded-lg border border-white/10 bg-ink-900 p-0.5">
          {[
            { id: "all", label: "Todos" },
            { id: "voice", label: "Voz" },
            { id: "whatsapp", label: "WhatsApp" },
            { id: "sms", label: "SMS" },
            { id: "email", label: "Email" },
          ].map((opt) => (
            <button
              key={opt.id}
              onClick={() => setChannelFilter(opt.id)}
              className={`px-3 py-1.5 text-xs rounded-md transition-colors ${
                channelFilter === opt.id ? "bg-white/10 text-ink-100" : "text-ink-400 hover:text-ink-200"
              }`}
            >
              {opt.label}
            </button>
          ))}
        </div>
      </div>

      {/* Grouped table — Day → Hour */}
      {groupOrder.map((groupLabel) => {
        const items = grouped[groupLabel];
        if (!items || items.length === 0) return null;

        // Sub-group by hour (descending)
        const byHour = {};
        for (const i of items) {
          const h = new Date(i.date).getHours();
          const hKey = `${String(h).padStart(2, "0")}:00`;
          if (!byHour[hKey]) byHour[hKey] = [];
          byHour[hKey].push(i);
        }
        const hourKeys = Object.keys(byHour).sort().reverse();

        return (
          <div key={groupLabel} className="flex flex-col gap-1">
            <div className="flex items-center gap-2 mb-2 px-1">
              <span className="text-ink-400">{groupIcons[groupLabel]}</span>
              <span className="text-xs font-semibold text-ink-300 uppercase tracking-wider">{groupLabel}</span>
              <span className="text-[10px] text-ink-500 font-mono bg-white/5 px-1.5 py-0.5 rounded">{items.length}</span>
            </div>
            <div className="card rounded-xl overflow-hidden">
              <table className="w-full text-sm">
                <thead>
                  <tr className="text-left text-[10px] uppercase tracking-wider text-ink-500 border-b border-white/5 bg-white/2">
                    <th className="px-4 py-2.5 font-medium w-20">Hora</th>
                    <th className="px-4 py-2.5 font-medium">Paciente</th>
                    <th className="px-4 py-2.5 font-medium w-24">Dirección</th>
                    <th className="px-4 py-2.5 font-medium w-24">Resultado</th>
                    <th className="px-4 py-2.5 font-medium w-20 text-center">Turnos</th>
                    <th className="px-4 py-2.5 font-medium w-16 text-right">
                      <span className="sr-only">Ver</span>
                    </th>
                  </tr>
                </thead>
                <tbody>
                  {hourKeys.map((hKey, hIdx) => (
                    <React.Fragment key={hKey}>
                      {/* Hour separator */}
                      <tr>
                        <td colSpan={6} className="px-4 py-1.5 bg-white/2 border-b border-white/5">
                          <span className="text-[10px] font-mono text-ink-400 inline-flex items-center gap-1.5">
                            <I.Clock size={10} /> {hKey}
                            <span className="text-ink-600">·</span>
                            <span className="text-ink-500">{byHour[hKey].length} {byHour[hKey].length === 1 ? "llamada" : "llamadas"}</span>
                          </span>
                        </td>
                      </tr>
                      {byHour[hKey].map((i) => {
                        const p = patientById(i.patientId);
                        const { turns } = parseTranscript(i.summary);
                        const time = new Date(i.date);
                        const timeStr = `${String(time.getHours()).padStart(2, "0")}:${String(time.getMinutes()).padStart(2, "0")}`;
                        return (
                          <tr
                            key={i.id}
                            onClick={() => setModalId(i.id)}
                            className="border-b border-white/5 last:border-0 hover:bg-sky-500/5 cursor-pointer transition-colors group"
                          >
                            <td className="px-4 py-3">
                              <span className="font-mono text-xs text-ink-300">{timeStr}</span>
                            </td>
                            <td className="px-4 py-3">
                              <div className="flex items-center gap-2">
                                <span className="text-ink-100 font-medium">{p ? p.name : i.patientId}</span>
                                {p && <span className="text-[10px] text-ink-500 font-mono">{p.id}</span>}
                              </div>
                            </td>
                            <td className="px-4 py-3">
                              <Badge tone="default">
                                {i.direction === "outbound" ? <I.ArrowUpRight size={11} /> : <I.ArrowDownLeft size={11} />}
                                {i.direction === "outbound" ? "Saliente" : "Entrante"}
                              </Badge>
                            </td>
                            <td className="px-4 py-3">
                              <span className={`text-xs ${
                                i.outcome === "contacted" ? "text-emerald-300" :
                                i.outcome === "no_answer" ? "text-amber-300" :
                                "text-ink-400"
                              }`}>{outcomeLabel(i.outcome)}</span>
                            </td>
                            <td className="px-4 py-3 text-center">
                              {turns.length > 0 ? (
                                <span className="inline-flex items-center gap-1 text-xs text-ink-300">
                                  <I.MessageSquare size={11} /> {turns.length}
                                </span>
                              ) : (
                                <span className="text-xs text-ink-500">—</span>
                              )}
                            </td>
                            <td className="px-4 py-3 text-right">
                              <span className="text-ink-500 group-hover:text-sky-300 transition-colors">
                                <I.ChevronRight size={14} />
                              </span>
                            </td>
                          </tr>
                        );
                      })}
                    </React.Fragment>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        );
      })}
      {filtered.length === 0 && <Empty>Sin llamadas que coincidan</Empty>}

      {/* Transcript Modal */}
      {modalInteraction && (
        <div className="fixed inset-0 z-[70] flex items-center justify-center fade-in">
          <div className="absolute inset-0 bg-black/60 backdrop-blur-sm" onClick={() => setModalId(null)} />
          <div className="relative w-full max-w-lg mx-4 card rounded-2xl overflow-hidden shadow-2xl border border-white/10 flex flex-col" style={{ maxHeight: "80vh" }}>
            {/* Modal header */}
            <div className="px-5 py-4 bg-ink-800/80 border-b border-white/5 shrink-0">
              <div className="flex items-center justify-between">
                <div>
                  <h3 className="text-sm font-semibold text-ink-100 flex items-center gap-2">
                    {modalPatient ? modalPatient.name : modalInteraction.patientId}
                    <Badge tone="default">
                      {modalInteraction.direction === "outbound" ? <I.ArrowUpRight size={11} /> : <I.ArrowDownLeft size={11} />}
                      {modalInteraction.direction === "outbound" ? "Saliente" : "Entrante"}
                    </Badge>
                  </h3>
                  <div className="text-[11px] text-ink-400 mt-0.5 flex items-center gap-2 font-mono">
                    <span>{fmtDateTime(modalInteraction.date)}</span>
                    <span className="text-ink-600">·</span>
                    <span>{outcomeLabel(modalInteraction.outcome)}</span>
                    {modalParsed.turns.length > 0 && (
                      <>
                        <span className="text-ink-600">·</span>
                        <span>{modalParsed.turns.length} turnos</span>
                      </>
                    )}
                  </div>
                </div>
                <button
                  onClick={() => setModalId(null)}
                  className="w-7 h-7 rounded-lg hover:bg-white/10 inline-flex items-center justify-center text-ink-400 hover:text-ink-200 transition-colors"
                >
                  <I.X size={16} />
                </button>
              </div>
            </div>

            {/* Transcript */}
            <div className="flex-1 overflow-y-auto px-5 py-4 bg-ink-950/60">
              {modalParsed.header && (
                <div className="text-xs text-ink-400 mb-4 pb-3 border-b border-white/5">{modalParsed.header}</div>
              )}
              {modalParsed.turns.length > 0 ? (
                <div className="flex flex-col gap-2.5">
                  {modalParsed.turns.map((t, idx) => {
                    // Tool call bubble — centered, purple accent
                    if (t.speaker === "tool_call") {
                      return (
                        <div key={idx} className="flex justify-center">
                          <div className="inline-flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-mono max-w-[85%]"
                            style={{ background: "rgba(139, 92, 246, 0.08)", border: "1px solid rgba(139, 92, 246, 0.2)" }}>
                            <I.Wrench size={11} className="text-violet-400 shrink-0" />
                            <span className="text-violet-300 break-all">{t.text}</span>
                          </div>
                        </div>
                      );
                    }
                    // Tool result bubble — centered, emerald accent
                    if (t.speaker === "tool_result") {
                      return (
                        <div key={idx} className="flex justify-center">
                          <div className="inline-flex items-start gap-2 px-3 py-2 rounded-lg text-xs font-mono max-w-[85%]"
                            style={{ background: "rgba(52, 211, 153, 0.06)", border: "1px solid rgba(52, 211, 153, 0.2)" }}>
                            <I.Check size={11} className="text-emerald-400 shrink-0 mt-0.5" />
                            <span className="text-emerald-300/80 break-all" style={{ fontSize: "11px" }}>{t.text}</span>
                          </div>
                        </div>
                      );
                    }
                    // Normal user/bot bubbles
                    return (
                      <div key={idx} className={`flex ${t.speaker === "bot" ? "justify-start" : "justify-end"}`}>
                        <div className={`bubble ${
                          t.speaker === "bot"
                            ? "bg-sky-500/10 text-ink-100 ring-1 ring-sky-500/20 rounded-tl-sm"
                            : "bg-white/5 text-ink-100 ring-1 ring-white/10 rounded-tr-sm"
                        }`}>
                          <div className="text-[10px] uppercase tracking-wider opacity-60 mb-1">
                            {t.speaker === "bot" ? "🤖 Clara" : `👤 ${modalPatient ? modalPatient.name.split(" ")[0] : "Paciente"}`}
                          </div>
                          {t.text}
                        </div>
                      </div>
                    );
                  })}
                </div>
              ) : (
                <div className="flex items-center justify-center py-8 text-ink-500 text-xs">
                  Sin transcripción disponible
                </div>
              )}
            </div>

            {/* Modal footer */}
            <div className="px-5 py-3 bg-ink-800/50 border-t border-white/5 flex items-center justify-between shrink-0">
              {modalPatient && (
                <button
                  onClick={() => { onSelectPatient(modalPatient); setModalId(null); }}
                  className="text-xs text-sky-300 hover:text-sky-200 inline-flex items-center gap-1"
                >
                  <I.Users size={12} /> Ver ficha del paciente
                </button>
              )}
              <button
                onClick={() => setModalId(null)}
                className="text-xs text-ink-400 hover:text-ink-200 px-3 py-1.5 rounded-lg hover:bg-white/5 transition-colors ml-auto"
              >
                Cerrar
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// =========================
// ESCALATIONS
// =========================
function EscalationsView({ data, onSelectPatient, onResolve }) {
  const [tab, setTab] = React.useState("pending");
  const escalations = data.escalations || [];
  const filtered = [...escalations]
    .filter((e) => e.status === tab)
    .sort((a, b) => new Date(b.date) - new Date(a.date));

  const patientById = (id) => (data.patients || []).find((p) => p.id === id);

  return (
    <div className="flex flex-col gap-5">
      <SectionHeader
        title="Escalaciones"
        subtitle="Registro interno"
      />
      <div className="inline-flex rounded-lg border border-white/10 bg-ink-900 p-0.5 self-start">
        {[
          { id: "pending", label: "Pendientes" },
          { id: "resolved", label: "Resueltas" },
        ].map((opt) => (
          <button
            key={opt.id}
            onClick={() => setTab(opt.id)}
            className={`px-3 py-1.5 text-xs rounded-md transition-colors ${
              tab === opt.id ? "bg-white/10 text-ink-100" : "text-ink-400 hover:text-ink-200"
            }`}
          >
            {opt.label} <span className="opacity-60 ml-1">{escalations.filter((e) => e.status === opt.id).length}</span>
          </button>
        ))}
      </div>

      <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
        {filtered.map((e) => {
          const p = patientById(e.patientId);
          return (
            <div key={e.id} className="card rounded-xl p-4 card-hover">
              <div className="flex items-start justify-between gap-3">
                <div className="flex-1 min-w-0">
                  <div className="flex items-center gap-2 flex-wrap">
                    <button
                      onClick={() => p && onSelectPatient(p)}
                      className="text-sm font-medium text-ink-100 hover:text-sky-300 truncate"
                    >
                      {p ? p.name : e.patientId}
                    </button>
                    {p && <PriorityBadge priority={p.priority} />}
                  </div>
                  <div className="text-[11px] text-ink-500 font-mono mt-0.5">{e.id} · {fmtDateTime(e.date)}</div>
                </div>
                <UrgencyBadge urgency={e.urgency} />
              </div>
              <p className="text-sm text-ink-300 mt-3 leading-relaxed">{e.reason}</p>
              <div className="flex items-center justify-between mt-4 pt-3 border-t border-white/5">
                <span className="text-xs text-ink-400 inline-flex items-center gap-2">
                  <span className="w-5 h-5 rounded-full bg-sky-500/15 text-sky-200 inline-flex items-center justify-center text-[10px] font-semibold">
                    {e.assignedTo[0]}
                  </span>
                  Asignado a {e.assignedTo}
                </span>
                {e.status === "pending" ? (
                  <Btn size="sm" icon={<I.Check size={12} />} onClick={() => onResolve(e.id)}>Marcar resuelta</Btn>
                ) : (
                  <Badge tone="emerald" icon={<I.Check size={11} />}>Resuelta</Badge>
                )}
              </div>
            </div>
          );
        })}
        {filtered.length === 0 && <div className="md:col-span-2"><Empty>Sin escalaciones {tab === "pending" ? "pendientes" : "resueltas"}</Empty></div>}
      </div>
    </div>
  );
}

// =========================
// SCHEDULE
// =========================
function ScheduleView({ onCall, onSelectPatient }) {
  const [schedule, setSchedule] = React.useState(null);
  const [loading, setLoading] = React.useState(true);

  React.useEffect(() => {
    let cancelled = false;
    async function load() {
      try {
        const r = await fetch(`${CLARA_API}/api/schedule`, { cache: "no-store" });
        if (!r.ok) throw new Error("HTTP " + r.status);
        const data = await r.json();
        if (!cancelled) setSchedule(data);
      } catch (err) {
        console.error("Schedule fetch error:", err);
      } finally {
        if (!cancelled) setLoading(false);
      }
    }
    load();
    const id = setInterval(load, 10000);
    return () => { cancelled = true; clearInterval(id); };
  }, []);

  if (loading) {
    return (
      <div className="flex items-center justify-center py-32 text-ink-500 text-sm">
        <span className="inline-flex items-center gap-2">
          <I.Refresh size={14} className="animate-spin" /> Cargando programación…
        </span>
      </div>
    );
  }

  const groups = schedule?.schedule || {};
  const total = schedule?.total || 0;

  const groupMeta = {
    vencidas: { icon: <I.AlertTriangle size={14} />, color: "text-rose-300", bg: "bg-rose-500/10", ring: "ring-rose-500/20", label: "Vencidas — contactar hoy" },
    "mañana": { icon: <I.Clock size={14} />, color: "text-amber-300", bg: "bg-amber-500/10", ring: "ring-amber-500/20", label: "Mañana" },
    "próximos 3 días": { icon: <I.Calendar size={14} />, color: "text-sky-300", bg: "bg-sky-500/10", ring: "ring-sky-500/20", label: "Próximos 3 días" },
    "esta semana": { icon: <I.Calendar size={14} />, color: "text-sky-300", bg: "bg-sky-500/10", ring: "ring-sky-500/20", label: "Esta semana" },
    "próxima semana": { icon: <I.Calendar size={14} />, color: "text-ink-300", bg: "bg-white/5", ring: "ring-white/10", label: "Próxima semana" },
    "más adelante": { icon: <I.Clock size={14} />, color: "text-ink-400", bg: "bg-white/3", ring: "ring-white/5", label: "Más adelante" },
  };

  return (
    <div className="flex flex-col gap-6">
      <SectionHeader
        title="Programación"
        subtitle={`${total} pacientes en seguimiento automático`}
        action={
          <div className="flex items-center gap-2 text-xs text-ink-400 font-mono">
            <span className="w-1.5 h-1.5 rounded-full bg-emerald-400 pulse-dot"></span>
            Dispatcher activo
          </div>
        }
      />

      {Object.keys(groups).length === 0 && (
        <Empty>Todos los pacientes están al día ✓</Empty>
      )}

      {Object.entries(groups).map(([groupKey, patients]) => {
        const meta = groupMeta[groupKey] || groupMeta["más adelante"];
        return (
          <div key={groupKey} className="flex flex-col gap-2">
            {/* Group header */}
            <div className="flex items-center gap-2.5 mb-1">
              <span className={`w-7 h-7 rounded-lg ${meta.bg} ${meta.color} inline-flex items-center justify-center`}>
                {meta.icon}
              </span>
              <div className="flex-1">
                <div className={`text-sm font-semibold ${meta.color}`}>{meta.label}</div>
              </div>
              <span className={`text-[11px] font-mono px-2 py-0.5 rounded-md ${meta.bg} ${meta.color} ring-1 ${meta.ring}`}>
                {patients.length}
              </span>
            </div>

            {/* Patient cards */}
            {patients.map((p) => {
              const pc = priorityClass(p.priority);
              const cm = channelMeta(p.contactPreference);
              const PrefIcon = I[cm.icon];
              return (
                <div
                  key={p.id}
                  onClick={() => onSelectPatient(p)}
                  className="card rounded-xl p-4 card-hover cursor-pointer flex items-center gap-4 transition-colors"
                >
                  <div className="flex-1 min-w-0">
                    <div className="flex items-center gap-2 flex-wrap">
                      <span className="text-sm text-ink-100 font-medium">{p.name}</span>
                      <PriorityBadge priority={p.priority} />
                      <span className={`inline-flex items-center justify-center w-4 h-4 rounded ${cm.bg} ${cm.color}`} title={cm.label}>
                        <PrefIcon size={10} />
                      </span>
                    </div>
                    <div className="text-[11px] text-ink-400 mt-1 flex items-center gap-2 font-mono">
                      <span>{p.id}</span>
                      <span className="text-ink-600">·</span>
                      <span>{p.equipmentType}</span>
                      <span className="text-ink-600">·</span>
                      <span>{p.region}</span>
                    </div>
                  </div>

                  <div className="flex flex-col items-end gap-1 shrink-0">
                    {p.daysUntilContact <= 0 ? (
                      <span className="text-xs font-mono text-rose-300 bg-rose-500/10 px-2 py-0.5 rounded ring-1 ring-rose-500/20">
                        +{Math.abs(p.daysUntilContact)} d vencida
                      </span>
                    ) : (
                      <span className="text-xs font-mono text-ink-300">
                        en {p.daysUntilContact} d
                      </span>
                    )}
                    <span className="text-[10px] text-ink-500">{p.nextContactDate}</span>
                  </div>

                  <CallButton patient={p} onCall={onCall} />
                </div>
              );
            })}
          </div>
        );
      })}
    </div>
  );
}


// =========================
// EQUIPMENT CATALOG
// =========================
function EquipmentView({ data }) {
  const types = data.equipmentTypes || [];
  const patients = data.patients || [];
  return (
    <div className="flex flex-col gap-5">
      <SectionHeader title="Catálogo de equipos" subtitle="Tipos de equipo médico que gestiona Oximesa" />
      <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
        {types.map((t) => {
          const count = patients.filter((p) => p.equipmentType === t.name).length;
          const overdue = patients.filter((p) => p.equipmentType === t.name && isOverdue(p)).length;
          const c = priorityClass(t.priority);
          return (
            <div key={t.id} className="card rounded-xl p-5 card-hover flex flex-col gap-3">
              <div className="flex items-start justify-between gap-3">
                <div className="flex items-start gap-3">
                  <span className={`w-10 h-10 rounded-lg ${c.bg} ${c.text} inline-flex items-center justify-center`}>
                    <I.Box size={18} />
                  </span>
                  <div>
                    <div className="flex items-center gap-2">
                      <h3 className="text-base font-semibold text-ink-100">{t.name}</h3>
                      <span className="text-[11px] font-mono text-ink-500">{t.id}</span>
                    </div>
                    <div className="mt-1"><PriorityBadge priority={t.priority} /></div>
                  </div>
                </div>
                <div className="text-right">
                  <div className="text-2xl font-semibold text-ink-100 tabular-nums">{count}</div>
                  <div className="text-[11px] text-ink-500">en espera</div>
                </div>
              </div>
              <p className="text-sm text-ink-400 leading-relaxed">{t.description}</p>
              {overdue > 0 && (
                <div className="flex items-center gap-2 text-xs text-amber-300 bg-amber-500/5 ring-1 ring-amber-500/20 rounded-lg px-3 py-2">
                  <I.AlertTriangle size={12} />
                  {overdue} {overdue === 1 ? "paciente sobrepasa" : "pacientes sobrepasan"} la frecuencia de contacto
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

Object.assign(window, {
  OverviewView, PatientsView, InteractionsView, EscalationsView, EquipmentView, ScheduleView,
});
