// ─── Directorio · Particulares (Pacientes) — lista + detalle (8 secciones) ─
// ParticularesScreen (lista, sobre EntityListScreen) + ParticularDetailScreen
// (detalle read-only + Editar → RecordFormScreen). Movido a screens/
// directorio/ (P10, junto con entidades.jsx/medicos.jsx — mismo esqueleto
// sobre dir-kit). Sin fixes de lógica en este paquete (solo mudanza):
// `parExpedientesCount` ya deriva correctamente por id (particularId), sin el
// bug de comprasEnt-por-nombre que sí tenía entidades.jsx. Expone a window:
// ParticularesScreen, ParticularDetailScreen, parExpedientesCount. Consume
// window.PARTICULARES/ENTIDADES/MEDICOS/EXPEDIENTES (core/colecciones.js),
// EntityListScreen/useEntityStats (ui/entity-list.jsx), PAR_ESTADO_CFG
// (dominio/pipeline.js), dirCalcAge/Avatar/TablePill (ui/primitives.jsx /
// dir-kit.jsx), DirHeader/DirCard/DirFieldGrid/DirChip/DirRegistros/DirNotas
// (ui/dir-kit.jsx).
//
// FIX P13 (ítem 17, anti-patrón `|| PARTICULARES[0]` residual): mismo fix que
// EntidadDetailScreen/MedicoDetailScreen — guard de fetch-and-merge (molde de
// InventarioDetailScreen, P10) en vez de caer silenciosamente a
// PARTICULARES[0] si `particularId` no está en la ventana hidratada.
const { useState: _useStateParD, useEffect: _useEffectParD } = React;

// Conteo de expedientes de un paciente, derivado en vivo de EXPEDIENTES (regla
// CLAUDE.md: los conteos se derivan, nunca se hardcodean). Reemplaza al campo
// estático p.expedientes que se calcula al cargar y no refleja lo creado en sesión.
function parExpedientesCount(p) {
  return (window.EXPEDIENTES || []).filter((e) => e.particularId === p.id).length;
}

// ─── Lista ──────────────────────────────────────────
function ParticularesScreen({ onOpen, prefilter, onNew }) {
  // Conteo de expedientes por paciente DERIVADO en vivo de EXPEDIENTES (no del
  // campo estático p.expedientes, que se calcula al cargar y no ve lo creado en
  // la sesión). Así, un paciente creado dentro de un expediente ya cuenta 1.
  const parExpCount = parExpedientesCount;

  // Top coberturas (entidades con más afiliados en la base)
  const cobOpts = ENTIDADES.map(e => ({
    label: e.razonSocial, value: e.id,
    count: PARTICULARES.filter(p => p.coberturaActual?.entidadId === e.id).length,
  })).filter(o => o.count > 0).sort((a, b) => b.count - a.count);

  // FIX P13 (ítem 14, Review P10 MEDIA-2): "Sin actividad" ANTES se derivaba
  // client-side sobre PARTICULARES (ventana hidratada — 1000 filas cargadas hoy,
  // no el universo real de 1697) tomando la última actividad del SET CARGADO como
  // referencia. El número mostrado (1000) era literal `PARTICULARES.length`, no un
  // conteo real — y encima `ultima_actividad` está NULL en el 100% de las filas
  // reales (gap de la migración, verificado psql): corregir la ventana solo
  // cambiaría el número a "100% sin actividad" (=total, sin señal real). Mismo
  // caso que MedicosSection del dashboard (campo sin datos reales que lo
  // sostengan) — N/D honesto en vez de un número que no informa nada.
  const totalExpPar = PARTICULARES.reduce((s, p) => s + parExpCount(p), 0);

  // v_particulares_stats: {total, sumExpedientes, coberturas, porCobertura}
  // (porCobertura viene keyed por entidad_id::text). "Sin actividad >90d" no está
  // en la vista (depende de `ultimaActividad`, campo NULL en el 100% de los
  // datos reales — no vale la pena agregarla server-side, ver FIX arriba).
  const srvStats = window.useEntityStats('particulares');
  const kTotal = srvStats ? srvStats.total : PARTICULARES.length;
  const kSumExp = srvStats ? srvStats.sumExpedientes : totalExpPar;
  const kCoberturas = srvStats ? srvStats.coberturas : cobOpts.length;
  const kPorCobertura = srvStats ? (srvStats.porCobertura || {}) : null;
  const cobOptsEff = kPorCobertura
    ? ENTIDADES.map(e => ({ label: e.razonSocial, value: e.id, count: kPorCobertura[e.id] || 0 })).filter(o => o.count > 0).sort((a, b) => b.count - a.count)
    : cobOpts;

  return (
    <EntityListScreen
      eyebrow="Directorio · Particulares"
      rowChevron
      title="Particulares"
      description="Pacientes registrados con expedientes activos o históricos."
      primaryAction={{ label: 'Nuevo paciente', icon: IconPlus, onClick: onNew }}
      secondaryAction={{ label: 'Exportar', icon: IconDownload }}
      kpis={[
        { label: 'Registrados',         value: String(kTotal), deltaTone: 'neutral', icon: IconUsers },
        { label: 'Expedientes activos', value: String(kSumExp), deltaTone: 'neutral', icon: IconFileText },
        { label: 'Coberturas',          value: String(kCoberturas), deltaTone: 'neutral', icon: IconShield },
        { label: 'Sin actividad >90d',  value: 'N/D', icon: IconClock },
      ]}
      filterChips={{
        options: cobOptsEff,
        applyFilter: (p, v) => p.coberturaActual?.entidadId === v,
      }}
      columns={[
        { key: 'paciente', label: 'Paciente', width: 'minmax(190px, 1fr)',
          render: p => (
            <div className="flex items-center gap-3 min-w-0">
              <Avatar name={`${p.nombre} ${p.apellido}`} />
              <div className="min-w-0">
                <p className="text-[13px] font-bold truncate" style={{ color: 'var(--foreground)' }}>{p.nombre} {p.apellido}</p>
                <p className="font-mono text-[11px] font-bold tracking-wide uppercase mt-0.5" style={{ color: 'var(--accent)' }}>{p.publicId}</p>
              </div>
            </div>
          ),
        },
        { key: 'cobertura', label: 'Cobertura actual', width: 'minmax(170px, 1fr)',
          render: p => {
            const ent = ENTIDADES.find(e => e.id === p.coberturaActual?.entidadId);
            if (!ent) return <span style={{ color: 'var(--muted-foreground)', fontSize: 12, fontStyle: 'italic' }}>—</span>;
            return (
              <div className="min-w-0">
                <p className="text-[12.5px] font-bold truncate" style={{ color: 'var(--foreground)' }}>{ent.razonSocial}</p>
              </div>
            );
          },
        },
        { key: 'dni', label: 'DNI', width: 'minmax(120px, 1fr)',
          render: p => <span className="text-[12.5px] font-mono tabular-nums" style={{ color: 'var(--muted-foreground)' }}>{p.dni}</span> },
        { key: 'telefono', label: 'Teléfono', width: 'minmax(140px, 1fr)',
          render: p => <span className="text-[12px] font-mono tabular-nums" style={{ color: 'var(--muted-foreground)' }}>{p.telefono}</span> },
        { key: 'expedientes', label: 'Expedientes', width: 'minmax(110px, 1fr)',
          render: p => { const n = parExpCount(p); return <span className="text-[14px] font-extrabold tabular-nums" style={{ color: n > 0 ? 'var(--foreground)' : 'var(--muted-foreground)' }}>{n}</span>; } },
        { key: 'estado', label: 'Estado', width: 'minmax(120px, 1fr)',
          render: p => {
            const cfg = PAR_ESTADO_CFG[p.estado] || PAR_ESTADO_CFG.ACTIVO;
            return <TablePill label={cfg.label} tone={cfg.tone} />;
          },
        },
      ]}
      rows={PARTICULARES}
      collection="particulares"
      searchPlaceholder="Buscar por nombre, DNI o cobertura…"
      searchFilter={(p, q) =>
        `${p.nombre} ${p.apellido}`.toLowerCase().includes(q) ||
        (p.dni || '').toLowerCase().includes(q) ||
        (p.telefono || '').toLowerCase().includes(q) ||
        (p.email || '').toLowerCase().includes(q)
      }
      onRowClick={onOpen}
      prefilter={prefilter}
      dateField="fechaCreacion"
      exportFilename="Particulares"
      exportConfig={[
        { label: 'ID', value: (p) => p.publicId },
        { label: 'Nombre', value: (p) => `${p.nombre} ${p.apellido}` },
        { label: 'DNI', value: (p) => p.dni },
        { label: 'Teléfono', value: (p) => p.telefono || '' },
        { label: 'Email', value: (p) => p.email || '' },
        { label: 'Cobertura', value: (p) => { const e = ENTIDADES.find((x) => x.id === (p.coberturaActual && p.coberturaActual.entidadId)); return e ? e.razonSocial : ''; } },
        { label: 'Expedientes', value: (p) => parExpedientesCount(p) },
        { label: 'Estado', value: (p) => (PAR_ESTADO_CFG[p.estado] || {}).label || p.estado || '' },
      ]}
    />
  );
}

// ─── Detalle ────────────────────────────────────────
function ParticularDetailScreen({ particularId, onBack, navigator, onEdit }) {
  // Guard fetch-and-merge (ver header) — nunca PARTICULARES[0].
  const foundLocal = (window.PARTICULARES || []).find(x => x.id === particularId);
  const [, _setMergeTickPar] = _useStateParD(0);
  const [notFoundPar, setNotFoundPar] = _useStateParD(false);
  _useEffectParD(() => {
    if (foundLocal || !particularId) return undefined;
    let cancelled = false;
    fetch(`/api/particulares/${encodeURIComponent(particularId)}`, { credentials: 'same-origin' })
      .then((r) => (r.ok ? r.json() : Promise.reject(r.status)))
      .then((server) => {
        if (cancelled || !server || !server.id) throw new Error('sin id');
        const col = window.PARTICULARES || (window.PARTICULARES = []);
        if (!col.some((x) => x.id === server.id)) col.push(server);
        _setMergeTickPar((t) => t + 1);
      })
      .catch((err) => {
        if (cancelled) return;
        console.warn('[ParticularDetailScreen] fetch-and-merge', particularId, err);
        setNotFoundPar(true);
      });
    return () => { cancelled = true; };
  }, [particularId, foundLocal]);

  if (!foundLocal) {
    if (notFoundPar) {
      return (
        <div className="space-y-6 pt-2">
          <button onClick={onBack} className="flex items-center gap-2 text-[11px] font-bold uppercase tracking-[0.12em] cursor-pointer" style={{ color: 'var(--muted-foreground)' }}>
            <IconArrowLeft size={13} />Volver a Particulares
          </button>
          <p className="text-[14px] font-semibold" style={{ color: 'var(--muted-foreground)' }}>No se encontró el paciente.</p>
        </div>
      );
    }
    return null;
  }
  const p = foundLocal;
  const estCfg = PAR_ESTADO_CFG[p.estado] || PAR_ESTADO_CFG.ACTIVO;
  const edad = dirCalcAge(p.fechaNacimiento);
  const [exportToast, setExportToast] = _useStateParD(null);
  const coberturaEnt = ENTIDADES.find(e => e.id === p.coberturaActual?.entidadId);
  const medicosAtend = (p.medicosAtendieron || [])
    .map(id => MEDICOS.find(m => m.id === id))
    .filter(Boolean);

  // Datos personales
  const datosPersonales = [
    { label: 'Nombre',            value: p.nombre },
    { label: 'Apellido',          value: p.apellido },
    { label: 'DNI',               value: p.dni,                                                                            mono: true },
    { label: 'Fecha de nacim.',   value: p.fechaNacimiento ? `${formatDate(p.fechaNacimiento)} · ${edad} años` : '—',     mono: true },
    { label: 'Sexo',              value: p.sexo === 'F' ? 'Femenino' : p.sexo === 'M' ? 'Masculino' : '—' },
  ];

  // Contacto
  const contacto = [
    { label: 'Teléfono', value: p.telefono, mono: true },
    { label: 'Email',    value: p.email },
  ];

  // Contacto de emergencia
  const emergencia = p.contactoEmergencia ? [
    { label: 'Nombre',   value: p.contactoEmergencia.nombre },
    { label: 'Vínculo',  value: p.contactoEmergencia.vinculo },
    { label: 'Teléfono', value: p.contactoEmergencia.telefono, mono: true },
  ] : null;

  // Ubicación
  const ubicacion = [
    { label: 'Domicilio',  value: p.domicilio },
    { label: 'Localidad',  value: p.localidad },
    { label: 'Provincia',  value: p.provincia },
  ];

  return (
    <div className="space-y-7 pt-2">

      {/* Header */}
      <DirHeader
        backLabel="Volver a Particulares"
        eyebrow="Directorio · Particular"
        onBack={onBack}
        avatar={<Avatar name={`${p.nombre} ${p.apellido}`} size={64} />}
        title={`${p.nombre} ${p.apellido}`}
        subtitle={
          <>
            <span className="font-mono font-bold" style={{ color: 'var(--accent)' }}>{p.publicId}</span>
            <span className="mx-1.5 opacity-50">·</span>
            <span className="font-mono">DNI {p.dni}</span>
            {edad != null && <><span className="mx-1.5 opacity-50">·</span><span>{edad} años</span></>}
          </>
        }
        statusLabel={estCfg.label}
        statusTone={estCfg.tone}
        actions={<>
          {/* FIX MEDIA "Exportar de detalle de Particular": wired de verdad
              (dirExportRegistro, ui/dir-kit.jsx) — antes sin onClick. */}
          <button className="btn btn-outline" onClick={() => {
            const grupos = [datosPersonales, contacto, ubicacion];
            if (emergencia) grupos.push(emergencia);
            const res = dirExportRegistro(`Particular ${p.publicId}`, grupos);
            setExportToast(`Exportado · 1 fila${res.format === 'csv' ? ' (CSV)' : ''}`);
            setTimeout(() => setExportToast(null), 3600);
          }}><IconDownload size={15} /><span className="hidden sm:inline">Exportar</span></button>
          <button className="btn btn-primary" onClick={() => onEdit && onEdit()}><IconPencil size={14} /><span className="hidden sm:inline">Editar</span></button>
        </>}
      />

      {/* Datos personales */}
      <DirCard eyebrow="Datos personales">
        <DirFieldGrid fields={datosPersonales} />
      </DirCard>

      {/* Contacto + Contacto de emergencia (a 2 columnas solo si hay emergencia; si no, Contacto ocupa el ancho) */}
      <div className={emergencia ? "grid grid-cols-1 lg:grid-cols-2 gap-6" : ""}>
        <DirCard eyebrow="Contacto">
          <DirFieldGrid fields={contacto} cols={3} />
        </DirCard>
        {emergencia && (
          <DirCard eyebrow="Contacto de emergencia">
            <DirFieldGrid fields={emergencia} cols={3} />
          </DirCard>
        )}
      </div>

      {/* Ubicación */}
      <DirCard eyebrow="Ubicación">
        <DirFieldGrid fields={ubicacion} cols={3} />
      </DirCard>

      {/* Cobertura actual */}
      <DirCard eyebrow="Cobertura actual">
        {coberturaEnt ? (
          <div className="grid grid-cols-1 sm:grid-cols-3 gap-x-8 gap-y-6">
            <div className="space-y-2 min-w-0">
              <p className="text-[10.5px] font-bold uppercase tracking-[0.14em]" style={{ color: 'var(--muted-foreground)' }}>Entidad</p>
              <button onClick={() => navigator && navigator.toEntidad(coberturaEnt.id)}
                className="text-left block transition-colors"
                style={{ color: 'var(--accent)' }}
                onMouseEnter={e => e.currentTarget.style.textDecoration = 'underline'}
                onMouseLeave={e => e.currentTarget.style.textDecoration = 'none'}>
                <p className="text-[15.5px] font-extrabold leading-snug">{coberturaEnt.razonSocial}</p>
                <p className="text-[11px] font-bold uppercase tracking-[0.06em] mt-0.5" style={{ color: 'var(--muted-foreground)' }}>
                  {coberturaEnt.tipo}
                </p>
              </button>
            </div>
            <div className="space-y-2 min-w-0">
              <p className="text-[10.5px] font-bold uppercase tracking-[0.14em]" style={{ color: 'var(--muted-foreground)' }}>Plan</p>
              <p className="text-[15.5px] font-extrabold leading-snug" style={{ color: 'var(--foreground)' }}>{p.coberturaActual.plan}</p>
            </div>
            <div className="space-y-2 min-w-0">
              <p className="text-[10.5px] font-bold uppercase tracking-[0.14em]" style={{ color: 'var(--muted-foreground)' }}>N° afiliado</p>
              <p className="text-[15.5px] font-extrabold leading-snug font-mono tabular-nums" style={{ color: 'var(--foreground)' }}>
                {p.coberturaActual.numeroAfiliado}
              </p>
            </div>
            <div className="space-y-2 min-w-0">
              <p className="text-[10.5px] font-bold uppercase tracking-[0.14em]" style={{ color: 'var(--muted-foreground)' }}>Vigencia</p>
              <p className="text-[15.5px] font-extrabold leading-snug font-mono tabular-nums" style={{ color: 'var(--foreground)' }}>
                {formatDate(p.coberturaActual.vigencia)}
              </p>
            </div>
          </div>
        ) : (
          <p className="text-[13px] italic" style={{ color: 'var(--muted-foreground)' }}>Sin cobertura registrada.</p>
        )}
      </DirCard>

      {/* Historial de coberturas */}
      {p.historialCoberturas && p.historialCoberturas.length > 0 && (
        <DirCard eyebrow={`Historial de coberturas · ${p.historialCoberturas.length}`}>
          <div className="rounded-xl overflow-hidden" style={{ border: '1px solid color-mix(in oklab, var(--border) 55%, transparent)' }}>
            <div className="grid items-center gap-4 px-4 py-3 text-[10.5px] font-bold uppercase tracking-[0.08em]"
              style={{ gridTemplateColumns: '1.6fr 1fr 130px 130px', color: 'var(--muted-foreground)', borderBottom: '1px solid color-mix(in oklab, var(--border) 55%, transparent)', background: 'color-mix(in oklab, var(--surface) 50%, transparent)' }}>
              <div>Entidad</div>
              <div>Plan</div>
              <div>Desde</div>
              <div>Hasta</div>
            </div>
            {p.historialCoberturas.map((h, i) => {
              const ent = ENTIDADES.find(e => e.id === h.entidadId);
              const isLast = i === p.historialCoberturas.length - 1;
              return (
                <div key={i} className="grid items-center gap-4 px-4 py-3.5"
                  style={{ gridTemplateColumns: '1.6fr 1fr 130px 130px', borderBottom: !isLast ? '1px solid color-mix(in oklab, var(--border) 45%, transparent)' : 'none' }}>
                  <button onClick={() => ent && navigator && navigator.toEntidad(ent.id)}
                    className="text-left text-[13px] font-bold truncate transition-colors"
                    style={{ color: ent ? 'var(--accent)' : 'var(--muted-foreground)' }}>
                    {ent?.razonSocial || '—'}
                  </button>
                  <span className="text-[12.5px] truncate" style={{ color: 'var(--foreground)' }}>{h.plan}</span>
                  <span className="text-[12px] font-mono tabular-nums" style={{ color: 'var(--muted-foreground)' }}>{formatDate(h.desde)}</span>
                  <span className="text-[12px] font-mono tabular-nums" style={{ color: 'var(--muted-foreground)' }}>{formatDate(h.hasta)}</span>
                </div>
              );
            })}
          </div>
        </DirCard>
      )}

      {/* Historial de médicos */}
      <DirCard eyebrow={`Historial de médicos · ${medicosAtend.length}`}>
        {medicosAtend.length > 0 ? (
          <div className="flex flex-wrap gap-2.5">
            {medicosAtend.map(m => (
              <DirChip key={m.id}
                label={`${m.titulo ? m.titulo + ' ' : ''}${m.nombre} ${m.apellido}`}
                sub={(m.especialidades || [m.especialidad])[0]}
                tone="accent"
                onClick={() => navigator && navigator.toMedico(m.id)}
              />
            ))}
          </div>
        ) : (
          <p className="text-[13px] italic" style={{ color: 'var(--muted-foreground)' }}>Aún no atendido por ningún médico registrado.</p>
        )}
      </DirCard>

      {/* Registros asociados */}
      <div className="space-y-3">
        <p className="text-[11px] font-bold uppercase tracking-[0.2em]" style={{ color: 'var(--accent)' }}>
          Registros asociados
        </p>
        <DirRegistros items={[
          { label: 'Expedientes', value: String(parExpedientesCount(p)), sublabel: parExpedientesCount(p) === 1 ? 'expediente' : 'expedientes', icon: <IconFileText size={16} />, onClick: () => navigator && navigator.toExpedientes({ particularId: p.id }) },
        ]} />
      </div>

      {/* Notas */}
      <DirNotas notas={p.notas} />

      <DirToast message={exportToast} />
    </div>
  );
}

Object.assign(window, { ParticularesScreen, ParticularDetailScreen });
