// ─────────────────────────────────────────────────────
// PARTES de trabajo — live SSE, historial y tokens.
// ─────────────────────────────────────────────────────

const fmtParteDate = (s) => {
  if (!s) return '—';
  const d = new Date(s);
  if (Number.isNaN(d.getTime())) return String(s).slice(0, 10);
  return d.toLocaleDateString('es-ES');
};

const fmtParteDateTime = (s) => {
  if (!s) return '—';
  const d = new Date(s);
  return Number.isNaN(d.getTime()) ? '—' : d.toLocaleString('es-ES');
};

const secondsAgo = (date) => {
  if (!date) return '—';
  const secs = Math.max(0, Math.floor((Date.now() - date.getTime()) / 1000));
  if (secs < 60) return `hace ${secs}s`;
  if (secs < 3600) return `hace ${Math.floor(secs / 60)}m`;
  return `hace ${Math.floor(secs / 3600)}h`;
};

const draftProgress = (row) => {
  const d = row.draft || {};
  let filled = 0;
  if (d.operario || row.operario_nombre) filled++;
  if (d.fecha) filled++;
  if (d.num_pedido) filled++;
  if (Array.isArray(d.desplazamiento) && d.desplazamiento.some(x => x.h_inicio || x.ruta || x.kms)) filled++;
  if (Array.isArray(d.instalacion) && d.instalacion.some(x => x.h_inicio || x.tarea)) filled++;
  return Math.round((filled / 5) * 100);
};

const buildWhatsappHref = (telefono, text) => {
  let phone = String(telefono || '').replace(/[\s\-().+]/g, '');
  if (phone && (phone.startsWith('6') || phone.startsWith('7'))) phone = `34${phone}`;
  return phone
    ? `https://wa.me/${phone}?text=${encodeURIComponent(text)}`
    : `https://wa.me/?text=${encodeURIComponent(text)}`;
};

const tokenLabels = {
  virgen: 'Sin usar',
  activo: 'Activo',
  caducado: 'Caducado',
  enviado: 'Enviado',
};

const tokenPill = (estado) => {
  if (estado === 'enviado') return 'ok';
  if (estado === 'activo') return 'info';
  if (estado === 'caducado') return 'err';
  return 'warn';
};

const PartesView = ({ user, onToast }) => {
  const [tab, setTab] = React.useState('live');
  const [drafts, setDrafts] = React.useState([]);
  const [liveState, setLiveState] = React.useState('connecting');
  const [lastEventAt, setLastEventAt] = React.useState(null);
  const [tick, setTick] = React.useState(0);
  const [hist, setHist] = React.useState([]);
  const [histLoading, setHistLoading] = React.useState(false);
  const [filters, setFilters] = React.useState({ search: '', operario: '', fecha_from: '', fecha_to: '' });
  const [selected, setSelected] = React.useState(() => new Set());
  const [openParteId, setOpenParteId] = React.useState(null);
  const [operarios, setOperarios] = React.useState([]);
  const [qr, setQr] = React.useState({ operario_id: '' });
  const [linkBusy, setLinkBusy] = React.useState(false);
  const [linkResult, setLinkResult] = React.useState(null);
  const [tokens, setTokens] = React.useState([]);
  const [tokensEstado, setTokensEstado] = React.useState('');
  const [tokensLoading, setTokensLoading] = React.useState(false);
  const isAdmin = user && user.rol === 'admin';

  React.useEffect(() => {
    API.get('/api/operarios')
      .then(rows => setOperarios(Array.isArray(rows) ? rows : []))
      .catch(() => {});
  }, []);

  React.useEffect(() => {
    const timer = setInterval(() => setTick(t => t + 1), 1000);
    return () => clearInterval(timer);
  }, []);

  React.useEffect(() => {
    if (tab !== 'live') return undefined;
    const token = API.getToken();
    if (!token) return undefined;
    let closed = false;
    setLiveState('connecting');
    const es = new EventSource(`/api/partes/drafts/stream?t=${encodeURIComponent(token)}`);
    es.onmessage = (ev) => {
      if (closed) return;
      try {
        const rows = JSON.parse(ev.data);
        setDrafts(Array.isArray(rows) ? rows : []);
        setLastEventAt(new Date());
        setLiveState('connected');
      } catch {
        setLiveState('stale');
      }
    };
    es.onerror = () => {
      if (!closed) setLiveState('stale');
    };
    return () => {
      closed = true;
      es.close();
    };
  }, [tab]);

  const loadHist = React.useCallback(() => {
    setHistLoading(true);
    const params = {};
    if (filters.operario) params.operario = filters.operario;
    if (filters.fecha_from) params.fecha_from = filters.fecha_from;
    if (filters.fecha_to) params.fecha_to = filters.fecha_to;
    if (filters.search && /^\s*\d+/.test(filters.search)) params.num_pedido = filters.search.trim();
    API.get('/api/partes', params)
      .then(rows => {
        const q = filters.search.trim().toLowerCase();
        const filtered = q
          ? rows.filter(r => [r.cliente, r.num_pedido, r.operario, r.nombre, String(r.id)].some(v => String(v || '').toLowerCase().includes(q)))
          : rows;
        setHist(Array.isArray(filtered) ? filtered : []);
        setSelected(new Set());
      })
      .catch(e => onToast && onToast(e.message || 'Error al cargar partes', true))
      .finally(() => setHistLoading(false));
  }, [filters, onToast]);

  React.useEffect(() => {
    if (tab === 'hist') loadHist();
  }, [tab, loadHist]);

  const loadTokens = React.useCallback(() => {
    if (!isAdmin) return;
    setTokensLoading(true);
    API.get('/api/partes/tokens', tokensEstado ? { estado: tokensEstado } : undefined)
      .then(rows => setTokens(Array.isArray(rows) ? rows : []))
      .catch(e => onToast && onToast(e.message || 'Error al cargar tokens', true))
      .finally(() => setTokensLoading(false));
  }, [isAdmin, tokensEstado, onToast]);

  React.useEffect(() => {
    if (tab === 'link') loadTokens();
  }, [tab, loadTokens]);

  const setFilter = (k, v) => setFilters(f => ({ ...f, [k]: v }));

  const exportUrl = (format) => {
    const path = `/api/partes/export/${format}`;
    if (selected.size > 0) return `${path}?ids=${Array.from(selected).join(',')}`;
    const params = new URLSearchParams();
    if (filters.operario) params.set('operario', filters.operario);
    if (filters.fecha_from) params.set('fecha_from', filters.fecha_from);
    if (filters.fecha_to) params.set('fecha_to', filters.fecha_to);
    if (filters.search && /^\s*\d+/.test(filters.search)) params.set('num_pedido', filters.search.trim());
    const qs = params.toString();
    return qs ? `${path}?${qs}` : path;
  };

  const exportHist = (format) => {
    const today = new Date().toISOString().slice(0, 10);
    const ext = format === 'excel' ? 'xlsx' : 'pdf';
    const filename = selected.size === 1 ? `parte_${Array.from(selected)[0]}.${ext}` : `partes_${today}.${ext}`;
    API.download(exportUrl(format), filename)
      .catch(e => onToast && onToast(e.message || 'Error al exportar', true));
  };

  const toggleSelected = (id) => {
    setSelected(prev => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });
  };

  const toggleAll = () => {
    setSelected(prev => prev.size === hist.length ? new Set() : new Set(hist.map(r => r.id)));
  };

  const generateLink = async () => {
    setLinkBusy(true);
    try {
      const data = await API.post('/api/partes/generate-link', { n: 1, operario_id: qr.operario_id || null });
      const url = data.urls && data.urls[0];
      if (!url) throw new Error('Respuesta vacía del servidor');
      const msg = `Hola, rellena el parte de trabajo aquí: ${url}`;
      setLinkResult({ url, waHref: buildWhatsappHref(data.telefono, msg) });
      onToast && onToast('Enlace generado ✓');
      loadTokens();
    } catch (e) {
      onToast && onToast(e.message || 'Error al generar enlace', true);
    } finally {
      setLinkBusy(false);
    }
  };

  const copyLink = async () => {
    if (!linkResult?.url) return;
    try {
      await navigator.clipboard.writeText(linkResult.url);
      onToast && onToast('Enlace copiado');
    } catch {
      onToast && onToast('No se pudo copiar', true);
    }
  };

  const cleanupTokens = async () => {
    if (!confirm('¿Eliminar todos los tokens sin usar y caducados?')) return;
    try {
      const r = await API.del('/api/partes/tokens/cleanup');
      onToast && onToast(`${r.deleted || 0} tokens eliminados`);
      loadTokens();
    } catch (e) {
      onToast && onToast(e.message || 'Error al limpiar tokens', true);
    }
  };

  const connected = liveState === 'connected';
  const allSelected = hist.length > 0 && selected.size === hist.length;

  return (
    <>
      <div className="page-h">
        <div>
          <h1>Partes de trabajo</h1>
          <div className="sub">Seguimiento de instalaciones en campo</div>
        </div>
        <div className="page-h-actions">
          <button className="btn" onClick={() => setTab('link')}><Icon name="phone" /> Enviar enlace</button>
          <button className="btn primary" onClick={() => setTab('live')}><Icon name="bolt" /> En vivo</button>
        </div>
      </div>

      <div className="subnav">
        <button className={tab==='live'?'on':''} onClick={()=>setTab('live')}>
          En curso
          <span className="ct">{drafts.length}</span>
        </button>
        <button className={tab==='hist'?'on':''} onClick={()=>setTab('hist')}>
          Historial
          <span className="ct">{hist.length}</span>
        </button>
        <button className={tab==='link'?'on':''} onClick={()=>setTab('link')}>Enviar enlace</button>
      </div>

      {tab === 'live' && (
        <>
          <div style={{display:'flex',alignItems:'center',gap:10,marginBottom:14,fontSize:12,color:'var(--ink-3)'}}>
            <span style={{display:'inline-block',width:8,height:8,borderRadius:'50%',background:connected ? 'var(--ok)' : 'var(--warn)'}}/>
            {connected ? `Live · actualizado ${secondsAgo(lastEventAt)}` : 'Live · reconectando…'}
            <span className="tb-spacer" style={{flex:1}}/>
            <button className="btn ghost sm" onClick={() => { setTab('hist'); setTimeout(() => setTab('live'), 0); }}>
              <Icon name="bolt" size={12}/> Reconectar
            </button>
          </div>

          {drafts.length === 0 ? (
            <div className="panel"><div className="panel-b muted" style={{fontSize:12.5}}>No hay partes en curso ahora mismo.</div></div>
          ) : (
            <div className="card-grid">
              {drafts.map((p, i) => {
                const d = p.draft || {};
                const pct = draftProgress(p);
                const op = d.operario || p.operario_nombre || 'Operario';
                const initialsText = op.split(' ').map(w=>w[0]).join('').slice(0,2).toUpperCase();
                return (
                  <div key={p.id || i} className="lcard">
                    <span className="live-dot" />
                    <div className="who">
                      <div className="avatar" style={{background:'var(--glass)'}}>{initialsText}</div>
                      <div>
                        <div className="n">{op}</div>
                        <div className="r">Operario instalador</div>
                      </div>
                    </div>
                    <div className="meta">
                      <strong>{d.cliente || 'Sin cliente'}</strong> · <span className="mono">{d.num_pedido || 'sin pedido'}</span>
                    </div>
                    <div className="progress">
                      <span className={`pbar ${pct===100?'ok':''}`}><i style={{width:`${pct}%`}}/></span>
                      <span className="pct">{pct}%</span>
                    </div>
                    <div className="last">Última actividad · {p.draft_updated_at ? secondsAgo(new Date(p.draft_updated_at)) : '—'}</div>
                  </div>
                );
              })}
            </div>
          )}
        </>
      )}

      {tab === 'hist' && (
        <>
          <div className="toolbar">
            <div className="tb-search">
              <Icon name="search" />
              <input placeholder="Cliente, operario, nº pedido…" value={filters.search} onChange={e=>setFilter('search', e.target.value)} onKeyDown={e=>{ if(e.key==='Enter') loadHist(); }}/>
            </div>
            <div className="tb-divider"/>
            <select className="chip" value={filters.operario} onChange={e=>setFilter('operario', e.target.value)}>
              <option value="">Operario</option>
              {operarios.map(o => <option key={o.id} value={o.nombre}>{o.nombre}</option>)}
            </select>
            <input className="chip" type="date" value={filters.fecha_from} onChange={e=>setFilter('fecha_from', e.target.value)} title="Desde"/>
            <input className="chip" type="date" value={filters.fecha_to} onChange={e=>setFilter('fecha_to', e.target.value)} title="Hasta"/>
            <button className="btn ghost" onClick={loadHist}><Icon name="search" size={12}/> Filtrar</button>
            <div className="tb-spacer"/>
            {selected.size > 0 && <span className="muted" style={{fontSize:12}}>{selected.size} seleccionados</span>}
            <button className="btn" onClick={() => exportHist('excel')}><Icon name="download"/> Excel</button>
            <button className="btn" onClick={() => exportHist('pdf')}><Icon name="file"/> PDF</button>
          </div>

          <div className="tbl-wrap">
            <div className="tbl-scroll">
              <table className="tbl">
                <thead>
                  <tr>
                    <th style={{width:32}}><span className={`ck ${allSelected?'on':''}`} onClick={toggleAll}/></th>
                    <th>#</th>
                    <th>Operario</th>
                    <th>Fecha</th>
                    <th>Cliente</th>
                    <th>Nº pedido</th>
                    <th>Enviado</th>
                    <th style={{width:32}}/>
                  </tr>
                </thead>
                <tbody>
                  {histLoading && <tr><td colSpan="8" style={{textAlign:'center',padding:24,color:'var(--ink-3)'}}>Cargando…</td></tr>}
                  {!histLoading && hist.length === 0 && <tr><td colSpan="8" style={{textAlign:'center',padding:24,color:'var(--ink-3)'}}>No hay partes enviados.</td></tr>}
                  {!histLoading && hist.map(p => (
                    <tr key={p.id} onClick={() => setOpenParteId(p.id)} className={selected.has(p.id) ? 'selected' : ''}>
                      <td onClick={e => { e.stopPropagation(); toggleSelected(p.id); }}>
                        <span className={`ck ${selected.has(p.id)?'on':''}`}/>
                      </td>
                      <td className="num strong">#{p.id}</td>
                      <td>{p.operario || '—'}</td>
                      <td className="num muted">{fmtParteDate(p.fecha)}</td>
                      <td className="strong">{p.cliente || '—'}</td>
                      <td className="num">{p.num_pedido || '—'}</td>
                      <td className="num muted">{fmtParteDateTime(p.submitted_at)}</td>
                      <td><button className="icon-btn" onClick={(e)=>{ e.stopPropagation(); setOpenParteId(p.id); }}><Icon name="eye" size={13}/></button></td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </>
      )}

      {tab === 'link' && (
        <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fit, minmax(280px, 1fr))',gap:14}}>
          <div className="panel">
            <div className="panel-h"><Icon name="phone"/> Enlace por WhatsApp</div>
            <div className="panel-b">
              <p className="muted" style={{marginBottom:14,fontSize:12.5}}>
                Genera un enlace único de un solo uso y envíalo al operario por WhatsApp.
              </p>
              <div className="field">
                <label>Operario</label>
                <select value={qr.operario_id} onChange={e=>setQr(q=>({...q,operario_id:e.target.value}))} style={parteInputStyle}>
                  <option value="">Cualquiera</option>
                  {operarios.map(o => <option key={o.id} value={o.id}>{o.nombre}</option>)}
                </select>
              </div>
              <div style={{display:'flex',gap:8,marginTop:14}}>
                <button className="btn" onClick={generateLink} disabled={linkBusy}><Icon name="sparkles"/> {linkBusy ? 'Generando…' : 'Generar enlace'}</button>
                {linkResult && <a className="btn glass" href={linkResult.waHref} target="_blank" rel="noreferrer"><Icon name="phone"/> WhatsApp</a>}
              </div>
              {linkResult && (
                <div style={{marginTop:14,display:'flex',gap:8,alignItems:'center'}}>
                  <div style={{flex:1,padding:10,background:'var(--surface-2)',border:'1px dashed var(--line-2)',borderRadius:6,fontFamily:'var(--font-mono)',fontSize:11,color:'var(--ink-3)',overflow:'hidden',textOverflow:'ellipsis'}}>
                    {linkResult.url}
                  </div>
                  <button className="btn ghost sm" onClick={copyLink}>Copiar</button>
                </div>
              )}
            </div>
          </div>

          {isAdmin && (
            <div className="panel" style={{gridColumn:'1 / -1',minWidth:0}}>
              <div className="panel-h">
                <Icon name="list"/> Registro de tokens
                <span className="badge">{tokens.length}</span>
              </div>
              <div className="panel-b">
                <div className="toolbar" style={{marginBottom:10}}>
                  <select className="chip" value={tokensEstado} onChange={e=>setTokensEstado(e.target.value)}>
                    <option value="">Todos</option>
                    <option value="virgen">Sin usar</option>
                    <option value="activo">Activos</option>
                    <option value="caducado">Caducados</option>
                    <option value="enviado">Enviados</option>
                  </select>
                  <button className="btn" onClick={loadTokens}><Icon name="search" size={12}/> Recargar</button>
                  <div className="tb-spacer"/>
                  <button className="btn ghost" onClick={cleanupTokens} style={{color:'var(--err)'}}><Icon name="trash" size={12}/> Limpiar</button>
                </div>
                <div className="tbl-wrap">
                  <table className="tbl">
                    <thead>
                      <tr><th>#</th><th>Estado</th><th>Token</th><th>Operario</th><th>Creado</th><th>Caduca / enviado</th></tr>
                    </thead>
                    <tbody>
                      {tokensLoading && <tr><td colSpan="6" style={{textAlign:'center',padding:18,color:'var(--ink-3)'}}>Cargando…</td></tr>}
                      {!tokensLoading && tokens.length === 0 && <tr><td colSpan="6" style={{textAlign:'center',padding:18,color:'var(--ink-3)'}}>No hay tokens.</td></tr>}
                      {!tokensLoading && tokens.map(t => (
                        <tr key={t.id}>
                          <td className="num strong">{t.id}</td>
                          <td><span className={`pill ${tokenPill(t.estado)}`}><span className="d"/>{tokenLabels[t.estado] || t.estado}</span></td>
                          <td className="mono">{t.token ? `${t.token.slice(0, 8)}…` : '—'}</td>
                          <td>{t.operario || '—'}</td>
                          <td className="num muted">{fmtParteDateTime(t.created_at)}</td>
                          <td className="num muted">{fmtParteDateTime(t.submitted_at || t.expires_at)}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              </div>
            </div>
          )}
        </div>
      )}

      <PartesDrawer
        parteId={openParteId}
        onClose={() => setOpenParteId(null)}
        onChanged={loadHist}
        onToast={onToast}
      />
    </>
  );
};

window.PartesView = PartesView;
