// Quote editor view

function QuoteView({ state, setState, totals, tweaks }) {
  const q = state.quote;
  const setQ = (patch) => setState(s => ({ ...s, quote: { ...s.quote, ...patch } }));
  const setClient = (patch) => setQ({ client: { ...q.client, ...patch } });
  const setCond = (patch) => setQ({ conditions: { ...q.conditions, ...patch } });
  const setProfit = (patch) => setQ({ profit: { ...(q.profit || { enabled: true, visible: true, percent: 10 }), ...patch } });

  // Quick modals for creating catalog entries on the fly
  const [newMatModal, setNewMatModal] = React.useState(null);  // { itemId|null, prefill }
  const [newRoleModal, setNewRoleModal] = React.useState(null); // { hhId|null, prefill }

  // Save a quote line item back to the materials catalog (or update existing match)
  const saveItemToCatalog = (it) => {
    if (!it.desc || !it.desc.trim()) {
      alert("Escribe una descripción antes de guardar este material en el catálogo.");
      return;
    }
    const existing = state.materials.find(m =>
      (it.sku && m.sku && m.sku.toLowerCase() === it.sku.toLowerCase()) ||
      (m.desc.toLowerCase() === it.desc.toLowerCase() && (m.unit || "") === (it.unit || ""))
    );
    const data = {
      sku: it.sku || (existing && existing.sku) || "",
      desc: it.desc,
      unit: it.unit || "un",
      price: +it.price || 0,
      margin: +it.margin || 0,
      cat: (existing && existing.cat) || "Sin categoría",
    };
    if (existing) {
      setState(s => ({
        ...s,
        materials: s.materials.map(m => m.id === existing.id ? { ...m, ...data } : m),
        quote: { ...s.quote, items: s.quote.items.map(x => x.id === it.id ? { ...x, mid: existing.id, sku: data.sku } : x) },
      }));
      window.__matSavedToast = `Material actualizado en catálogo: ${data.desc.slice(0,40)}`;
    } else {
      const m = { ...data, id: uid("m") };
      setState(s => ({
        ...s,
        materials: [m, ...s.materials],
        quote: { ...s.quote, items: s.quote.items.map(x => x.id === it.id ? { ...x, mid: m.id, sku: data.sku } : x) },
      }));
      window.__matSavedToast = `Material guardado en catálogo: ${data.desc.slice(0,40)}`;
    }
    setSavedToastAt(Date.now());
  };
  const [savedToastAt, setSavedToastAt] = React.useState(0);
  React.useEffect(() => {
    if (!savedToastAt) return;
    const t = setTimeout(() => setSavedToastAt(0), 2400);
    return () => clearTimeout(t);
  }, [savedToastAt]);

  // Items
  const updItem = (id, patch) => setQ({ items: q.items.map(i => i.id === id ? { ...i, ...patch } : i) });
  const delItem = (id) => setQ({ items: q.items.filter(i => i.id !== id) });
  const addItem = () => setQ({
    items: [...q.items, { id: uid("i"), mid: "", qty: 1, price: 0, margin: 20, desc: "", unit: "un", sku: "" }],
  });
  const pickMat = (id, mid) => {
    const m = state.materials.find(x => x.id === mid);
    if (!m) return;
    updItem(id, { mid, sku: m.sku, desc: m.desc, unit: m.unit, price: m.price, margin: m.margin });
  };

  // HH
  const updHH = (id, patch) => setQ({ hh: q.hh.map(h => h.id === id ? { ...h, ...patch } : h) });
  const delHH = (id) => setQ({ hh: q.hh.filter(h => h.id !== id) });
  const addHH = () => setQ({
    hh: [...q.hh, { id: uid("h"), rid: "", qty: 8, rate: 0, social: 40, role: "" }],
  });
  const pickRole = (id, rid) => {
    const r = state.roles.find(x => x.id === rid);
    if (!r) return;
    updHH(id, { rid, role: r.role, rate: r.rate, social: r.social != null ? r.social : 40 });
  };

  // Expenses (gastos generales)
  const expenses = q.expenses || [];
  const updExp = (id, patch) => setQ({ expenses: expenses.map(e => e.id === id ? { ...e, ...patch } : e) });
  const delExp = (id) => setQ({ expenses: expenses.filter(e => e.id !== id) });
  const addExp = () => setQ({
    expenses: [...expenses, { id: uid("e"), cat: "Arriendo de camioneta", desc: "", qty: 1, unit: "día", price: 0 }],
  });

  const profit = q.profit || { enabled: true, visible: true, percent: 10 };
  const [savedAt, setSavedAt] = React.useState(null);
  const [matPicker, setMatPicker] = React.useState(null); // { itemId } | null
  const [rolePicker, setRolePicker] = React.useState(null); // { hhId } | null
  const [clientPicker, setClientPicker] = React.useState(false);
  const [editClientModal, setEditClientModal] = React.useState(false);
  const [clientSavedAt, setClientSavedAt] = React.useState(0);

  // Auto-save client to catalog (debounced).
  // Runs whenever client fields change; only persists when there's enough
  // content (name OR rut) so we don't pollute the catalog with empty entries.
  React.useEffect(() => {
    const c = q.client || {};
    if (!c.name && !c.rut) return;
    const t = setTimeout(() => {
      setState(s => {
        const { clients } = window.upsertClient(s.clients || [], c);
        if (clients === s.clients) return s; // nothing changed
        return { ...s, clients };
      });
      setClientSavedAt(Date.now());
    }, 1200);
    return () => clearTimeout(t);
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [q.client?.name, q.client?.rut, q.client?.contact, q.client?.email, q.client?.phone, q.client?.address]);

  // Toast for client auto-save
  React.useEffect(() => {
    if (!clientSavedAt) return;
    const t = setTimeout(() => setClientSavedAt(0), 1800);
    return () => clearTimeout(t);
  }, [clientSavedAt]);

  const saveQuoteToHistory = () => {
    // Snapshot stores BOTH a summary (used by the dashboard list) AND the
    // full quote payload under `.data` so we can restore it intact later.
    // Deep-clone via JSON to avoid sharing references with the live editor
    // (otherwise edits after "save" would mutate the saved copy too).
    const fullData = JSON.parse(JSON.stringify(q));
    const snapshot = {
      id: q.id,
      client: q.client.name || "(Sin cliente)",
      project: q.projectName || "(Sin proyecto)",
      total: totals.total,
      status: q.status || "borrador",
      date: new Date().toISOString().slice(0, 10),
      data: fullData,
    };
    setState(s => {
      const others = (s.quotes || []).filter(x => x.id !== q.id);
      return { ...s, quotes: [snapshot, ...others] };
    });
    setSavedAt(new Date());
    setTimeout(() => setSavedAt(null), 2500);
  };

  return (
    <>
      <Topbar
        title={q.projectName || "Nueva cotización"}
        crumb={<>Cotización <span className="mono">{q.id}</span> · {statusBadge(q.status)}</>}
        actions={
          <>
            <select className="btn" value={q.status || "borrador"}
                    onChange={e => setQ({ status: e.target.value })}
                    style={{appearance:"auto",minWidth:140}}
                    title="Estado de la cotización">
              <option value="borrador">📝 Borrador</option>
              <option value="enviada">📤 Enviada</option>
              <option value="aprobada">✅ Aprobada (adjudicada)</option>
              <option value="rechazada">❌ Rechazada</option>
            </select>
            <button className="btn" onClick={() => setState(s => ({ ...s, quote: window.emptyQuote() }))}>
              <Icon.plus /> Nueva cotización
            </button>
            <button className="btn primary" onClick={saveQuoteToHistory}>
              <Icon.check /> {savedAt ? "Guardado ✓" : "Guardar cotización"}
            </button>
            <button className="btn dark" onClick={() => setState(s => ({...s, route:"print"}))}>
              <Icon.print /> Imprimir / Exportar
            </button>
          </>
        }
      />
      {savedToastAt > 0 && (
        <div style={{position:"fixed",top:18,right:18,zIndex:9999,
                     background:"var(--ok, #2e7d32)",color:"white",
                     padding:"10px 16px",borderRadius:8,fontWeight:600,fontSize:13,
                     boxShadow:"0 6px 20px rgba(0,0,0,.18)"}}>
          ✓ {window.__matSavedToast || "Guardado en catálogo"}
        </div>
      )}
      <div className="content">
        <div className="quote-layout">
          <div>
            {/* Cliente */}
            <div className="section-title">
              <span className="n">01</span>
              <h3>Datos del cliente</h3>
              <span className="hint">Se guarda automáticamente en el catálogo</span>
            </div>
            <div className="card">
              <div className="card-head">
                <div className="row" style={{gap:8,flexWrap:"wrap"}}>
                  {q.client?.name || q.client?.rut ? (
                    <span className="badge brand dot">
                      {clientSavedAt ? "✓ Guardado en clientes" : (q.client?.name || q.client?.rut)}
                    </span>
                  ) : (
                    <span className="hint">Sin cliente — empieza a escribir o búscalo del catálogo</span>
                  )}
                </div>
                <div className="row" style={{gap:6}}>
                  <button className="btn sm" onClick={() => setClientPicker(true)}>
                    <Icon.search size={14} /> Buscar cliente
                  </button>
                  <button className="btn sm" title="Editar este cliente en el catálogo"
                          onClick={() => setEditClientModal(true)}
                          disabled={!q.client?.name && !q.client?.rut}>
                    <Icon.edit /> Editar
                  </button>
                  <button className="btn sm" title="Limpiar datos del cliente en esta cotización"
                          onClick={() => setClient({ name: "", rut: "", contact: "", email: "", phone: "", address: "" })}>
                    <Icon.plus style={{transform:"rotate(45deg)"}} /> Limpiar
                  </button>
                </div>
              </div>
              <div className="card-body">
              <div className="grid-2">
                <div className="field">
                  <label>Razón social</label>
                  <input value={q.client.name} onChange={e => setClient({ name: e.target.value })} />
                </div>
                <div className="field">
                  <label>RUT</label>
                  <input value={q.client.rut} onChange={e => setClient({ rut: e.target.value })} />
                </div>
                <div className="field">
                  <label>Contacto</label>
                  <input value={q.client.contact} onChange={e => setClient({ contact: e.target.value })} />
                </div>
                <div className="field">
                  <label>Email</label>
                  <input value={q.client.email} onChange={e => setClient({ email: e.target.value })} />
                </div>
                <div className="field">
                  <label>Teléfono</label>
                  <input value={q.client.phone} onChange={e => setClient({ phone: e.target.value })} />
                </div>
                <div className="field">
                  <label>Dirección</label>
                  <input value={q.client.address} onChange={e => setClient({ address: e.target.value })} />
                </div>
              </div>
              <div className="grid-2" style={{marginTop: 14}}>
                <div className="field">
                  <label>Nombre del proyecto</label>
                  <input value={q.projectName} onChange={e => setQ({ projectName: e.target.value })} />
                </div>
                <div className="grid-2">
                  <div className="field">
                    <label>Fecha emisión</label>
                    <input type="date" value={q.createdAt} onChange={e => setQ({ createdAt: e.target.value })} />
                  </div>
                  <div className="field">
                    <label>Válida hasta</label>
                    <input type="date" value={q.validUntil} onChange={e => setQ({ validUntil: e.target.value })} />
                  </div>
                </div>
              </div>
            </div></div>

            {/* Materiales */}
            <div className="section-title">
              <span className="n">02</span>
              <h3>Detalle de materiales</h3>
              <span className="hint">{q.items.length} ítems · {clp(totals.matClient)} cliente</span>
            </div>
            <div className="card">
              <div className="card-head">
                <div className="row" style={{gap:8}}>
                  <span className="badge brand">Neto {clp(totals.matNet)}</span>
                  <span className="badge">Margen {clp(totals.matMarg)}</span>
                </div>
                <button className="btn primary sm" onClick={addItem}>
                  <Icon.plus /> Agregar material
                </button>
              </div>
              <div className="card-body" style={{padding:"8px 14px 0",borderBottom:"1px solid var(--line)"}}>
                <div className="muted" style={{fontSize:11.5,lineHeight:1.5}}>
                  💡 Usa <b>Buscar del catálogo</b> para insertar un material guardado, o escribe directamente uno nuevo en la fila y luego presiona <b><Icon.download size={11} /> Guardar en catálogo</b> para reutilizarlo en futuras cotizaciones.
                </div>
              </div>
              <div className="card-body flush" style={{overflow:"auto"}}>
                <table className="data">
                  <thead>
                    <tr>
                      <th style={{width: 220}}>Material (catálogo)</th>
                      <th>Descripción</th>
                      <th style={{width: 60}}>Un.</th>
                      <th style={{width: 90}} className="num">Cant.</th>
                      <th style={{width: 120}} className="num">Precio neto</th>
                      <th style={{width: 80}} className="num">Marg. %</th>
                      <th style={{width: 130}} className="num">Total cliente</th>
                      <th style={{width: 44}}></th>
                    </tr>
                  </thead>
                  <tbody>
                    {q.items.map(it => {
                      const inCatalog = !!it.mid && state.materials.some(m => m.id === it.mid);
                      const canSave = !!(it.desc && it.desc.trim()) && (+it.price > 0);
                      return (
                      <tr key={it.id}>
                        <td>
                          <button className="btn sm" style={{width:"100%",justifyContent:"flex-start",gap:6}}
                                  onClick={() => setMatPicker({ itemId: it.id })}>
                            <Icon.search size={14} />
                            <span style={{flex:1,textAlign:"left",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>
                              {it.sku ? `${it.sku} · ${it.desc.slice(0,30)}` : "Buscar del catálogo"}
                            </span>
                          </button>
                        </td>
                        <td>
                          <input value={it.desc} onChange={e => updItem(it.id, { desc: e.target.value })} />
                        </td>
                        <td>
                          <input value={it.unit} onChange={e => updItem(it.id, { unit: e.target.value })} />
                        </td>
                        <td className="num">
                          <input className="num" type="number" value={it.qty}
                                 onChange={e => updItem(it.id, { qty: +e.target.value })} />
                        </td>
                        <td className="num">
                          <input className="num" type="number" value={it.price}
                                 onChange={e => updItem(it.id, { price: +e.target.value })} />
                        </td>
                        <td className="num">
                          <input className="num" type="number" value={it.margin}
                                 onChange={e => updItem(it.id, { margin: +e.target.value })} />
                        </td>
                        <td className="num" style={{fontWeight:600}}>{clp(itemClient(it))}</td>
                        <td>
                          <div className="row" style={{gap:4}}>
                            <button className="btn icon" title={inCatalog ? "Actualizar este material en el catálogo" : "Guardar este material en el catálogo (para reusarlo)"}
                                    disabled={!canSave}
                                    onClick={() => saveItemToCatalog(it)}
                                    style={{color: inCatalog ? "var(--ok)" : "var(--brand-deep)"}}>
                              {inCatalog ? <Icon.check /> : <Icon.download />}
                            </button>
                            <button className="btn danger icon" onClick={() => delItem(it.id)} title="Eliminar">
                              <Icon.trash />
                            </button>
                          </div>
                        </td>
                      </tr>
                    );})}
                    {q.items.length === 0 && (
                      <tr><td colSpan={8}><div className="empty">Sin materiales. Agrega uno desde el catálogo.</div></td></tr>
                    )}
                  </tbody>
                </table>
              </div>
            </div>

            {/* HH */}
            <div className="section-title">
              <span className="n">03</span>
              <h3>Horas Hombre profesionales</h3>
              <span className="hint">{q.hh.length} roles · {clp(totals.hhTotal)}</span>
            </div>
            <div className="card">
              <div className="card-head">
                <div className="row" style={{gap:8}}>
                  <span className="badge deep">Base HH {clp(totals.hhBaseTot)}</span>
                  <span className="badge">Leyes soc. {clp(totals.hhSocTot)}</span>
                </div>
                <button className="btn primary sm" onClick={addHH}>
                  <Icon.plus /> Agregar rol
                </button>
              </div>
              <div className="card-body flush" style={{overflow:"auto"}}>
                <table className="data">
                  <thead>
                    <tr>
                      <th style={{width: 240}}>Rol / Perfil</th>
                      <th>Descripción / alcance</th>
                      <th style={{width: 80}} className="num">HH</th>
                      <th style={{width: 120}} className="num">Valor HH</th>
                      <th style={{width: 100}} className="num">Leyes soc. %</th>
                      <th style={{width: 130}} className="num">Subtotal</th>
                      <th style={{width: 44}}></th>
                    </tr>
                  </thead>
                  <tbody>
                    {q.hh.map(h => (
                      <tr key={h.id}>
                        <td>
                          <button className="btn sm" style={{width:"100%",justifyContent:"flex-start",gap:6}}
                                  onClick={() => setRolePicker({ hhId: h.id })}>
                            <Icon.search size={14} />
                            <span style={{flex:1,textAlign:"left",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>
                              {h.role || "Buscar perfil HH"}
                            </span>
                          </button>
                        </td>
                        <td>
                          <input value={h.notes || ""} placeholder="Ej: Levantamiento, diseño y puesta en servicio"
                                 onChange={e => updHH(h.id, { notes: e.target.value })} />
                        </td>
                        <td className="num">
                          <input className="num" type="number" value={h.qty}
                                 onChange={e => updHH(h.id, { qty: +e.target.value })} />
                        </td>
                        <td className="num">
                          <input className="num" type="number" value={h.rate}
                                 onChange={e => updHH(h.id, { rate: +e.target.value })} />
                        </td>
                        <td className="num">
                          <input className="num" type="number" value={h.social || 0}
                                 onChange={e => updHH(h.id, { social: +e.target.value })} />
                        </td>
                        <td className="num" style={{fontWeight:600}}>{clp(hhNet(h))}</td>
                        <td>
                          <button className="btn danger icon" onClick={() => delHH(h.id)}>
                            <Icon.trash />
                          </button>
                        </td>
                      </tr>
                    ))}
                    {q.hh.length === 0 && (
                      <tr><td colSpan={7}><div className="empty">Sin roles de HH.</div></td></tr>
                    )}
                  </tbody>
                </table>
              </div>
            </div>

            {/* Gastos generales */}
            <div className="section-title">
              <span className="n">04</span>
              <h3>Gastos generales</h3>
              <span className="hint">{expenses.length} ítems · {clp(totals.expTotal)}</span>
            </div>
            <div className="card">
              <div className="card-head">
                <div className="row" style={{gap:8}}>
                  <span className="badge deep">Total {clp(totals.expTotal)}</span>
                  <span className="hint">Arriendos, alojamientos, alimentación, combustible, etc.</span>
                </div>
                <button className="btn primary sm" onClick={addExp}>
                  <Icon.plus /> Agregar gasto
                </button>
              </div>
              <div className="card-body flush" style={{overflow:"auto"}}>
                <table className="data">
                  <thead>
                    <tr>
                      <th style={{width: 200}}>Categoría</th>
                      <th>Descripción</th>
                      <th style={{width: 80}} className="num">Cant.</th>
                      <th style={{width: 80}}>Unidad</th>
                      <th style={{width: 130}} className="num">Valor unit.</th>
                      <th style={{width: 130}} className="num">Subtotal</th>
                      <th style={{width: 44}}></th>
                    </tr>
                  </thead>
                  <tbody>
                    {expenses.map(e => (
                      <tr key={e.id}>
                        <td>
                          <select value={e.cat} onChange={ev => updExp(e.id, { cat: ev.target.value })}>
                            {(window.SEED_EXPENSES_CATS || []).map(c => <option key={c} value={c}>{c}</option>)}
                          </select>
                        </td>
                        <td>
                          <input value={e.desc} placeholder="Detalle"
                                 onChange={ev => updExp(e.id, { desc: ev.target.value })} />
                        </td>
                        <td className="num">
                          <input className="num" type="number" value={e.qty}
                                 onChange={ev => updExp(e.id, { qty: +ev.target.value })} />
                        </td>
                        <td>
                          <input value={e.unit}
                                 onChange={ev => updExp(e.id, { unit: ev.target.value })} />
                        </td>
                        <td className="num">
                          <input className="num" type="number" value={e.price}
                                 onChange={ev => updExp(e.id, { price: +ev.target.value })} />
                        </td>
                        <td className="num" style={{fontWeight:600}}>{clp(expenseNet(e))}</td>
                        <td>
                          <button className="btn danger icon" onClick={() => delExp(e.id)}>
                            <Icon.trash />
                          </button>
                        </td>
                      </tr>
                    ))}
                    {expenses.length === 0 && (
                      <tr><td colSpan={7}><div className="empty">Sin gastos generales cargados.</div></td></tr>
                    )}
                  </tbody>
                </table>
              </div>
            </div>

            {/* Utilidad */}
            <div className="section-title">
              <span className="n">05</span>
              <h3>Utilidad de la empresa</h3>
              <span className="hint">{profit.enabled ? `${profit.percent}% aplicado` : "desactivada"}</span>
            </div>
            <div className="card"><div className="card-body">
              <div className="grid-3" style={{gap: 14, alignItems: "end"}}>
                <div className="field">
                  <label>Activar utilidad</label>
                  <select value={profit.enabled ? "si" : "no"}
                          onChange={e => setProfit({ enabled: e.target.value === "si" })}>
                    <option value="si">Sí — aplicar al total</option>
                    <option value="no">No — sin utilidad</option>
                  </select>
                </div>
                <div className="field">
                  <label>Porcentaje (%)</label>
                  <input type="number" value={profit.percent || 0}
                         onChange={e => setProfit({ percent: +e.target.value })}
                         disabled={!profit.enabled} />
                </div>
                <div className="field">
                  <label>Mostrar línea al cliente</label>
                  <select value={profit.visible ? "si" : "no"}
                          onChange={e => setProfit({ visible: e.target.value === "si" })}>
                    <option value="si">Sí — visible en cotización</option>
                    <option value="no">No — oculta en impresión</option>
                  </select>
                </div>
              </div>
              <div style={{marginTop:14,padding:"12px 14px",background:"var(--surface-2)",borderRadius:8,fontSize:12,color:"var(--muted)",lineHeight:1.5}}>
                La utilidad se calcula sobre Materiales + HH + Gastos generales. Actualmente aplica <b>{clp(totals.profitAmt)}</b>.
                Si la ocultas, el valor se suma al total pero no aparece como línea separada en la impresión.
              </div>
            </div></div>

            {/* Condiciones */}
            <div className="section-title">
              <span className="n">06</span>
              <h3>Condiciones comerciales</h3>
            </div>
            <div className="card"><div className="card-body">
              <div className="grid-2">
                <div className="field">
                  <label>Forma de pago</label>
                  <textarea value={q.conditions.paymentTerms}
                            onChange={e => setCond({ paymentTerms: e.target.value })} />
                </div>
                <div className="field">
                  <label>Garantía</label>
                  <textarea value={q.conditions.warranty}
                            onChange={e => setCond({ warranty: e.target.value })} />
                </div>
                <div className="grid-2">
                  <div className="field">
                    <label>Plazo entrega (días hábiles)</label>
                    <input type="number" value={q.conditions.deliveryDays}
                           onChange={e => setCond({ deliveryDays: +e.target.value })} />
                  </div>
                  <div className="field">
                    <label>Validez (días)</label>
                    <input type="number" value={q.conditions.validity}
                           onChange={e => setCond({ validity: +e.target.value })} />
                  </div>
                </div>
                <div className="field">
                  <label>Observaciones / notas técnicas</label>
                  <textarea value={q.conditions.notes}
                            onChange={e => setCond({ notes: e.target.value })} />
                </div>
              </div>
            </div></div>
          </div>

          {/* Totals sticky panel */}
          <div className="totals-panel">
            <div style={{padding:"14px 18px 10px", borderBottom:"1px solid var(--line)"}}>
              <div className="muted" style={{fontSize:11,textTransform:"uppercase",letterSpacing:".1em",fontWeight:600}}>Resumen</div>
              <div style={{fontWeight:700,marginTop:4,fontSize:13}}>{q.id}</div>
            </div>
            <div className="row"><span>Materiales (cliente)</span><span>{clp(totals.matClient)}</span></div>
            <div className="row"><span>Horas Hombre</span><span>{clp(totals.hhTotal)}</span></div>
            <div className="row"><span>Gastos generales</span><span>{clp(totals.expTotal)}</span></div>
            {profit.enabled && (
              <div className="row strong"><span>Utilidad {profit.percent}%</span><span>{clp(totals.profitAmt)}</span></div>
            )}
            <div className="row"><span className="muted">Subtotal neto</span><span>{clp(totals.subtotal)}</span></div>
            {tweaks.ivaEnabled && (
              <div className="row"><span className="muted">IVA {totals.ivaRate}%</span><span>{clp(totals.iva)}</span></div>
            )}
            <div className="row total">
              <span>TOTAL{tweaks.ivaEnabled ? "" : " NETO"}</span>
              <span className="accent">{clp(totals.total)}</span>
            </div>
            <div style={{padding:"14px 18px"}}>
              <button className="btn primary" style={{width:"100%"}}
                      onClick={() => setState(s => ({...s, route:"print"}))}>
                <Icon.print /> Preparar impresión
              </button>
            </div>
          </div>
        </div>
      </div>
      {matPicker && (
        <MatPicker
          materials={state.materials}
          onClose={() => setMatPicker(null)}
          onCreateNew={(prefill) => {
            setNewMatModal({ itemId: matPicker.itemId, prefill });
            setMatPicker(null);
          }}
          onPick={(m) => {
            updItem(matPicker.itemId, { mid: m.id, sku: m.sku, desc: m.desc, unit: m.unit, price: m.price, margin: m.margin });
            setMatPicker(null);
          }}
        />
      )}
      {newMatModal && typeof MaterialModal === "function" && (
        <MaterialModal
          initial={{
            id: null, sku: "", desc: "", unit: "un", price: 0, margin: 20,
            cat: "Sin categoría",
            ...(newMatModal.prefill || {}),
          }}
          onClose={() => setNewMatModal(null)}
          onSave={(data) => {
            const m = { ...data, id: uid("m") };
            setState(s => {
              const items = newMatModal.itemId
                ? s.quote.items.map(it => it.id === newMatModal.itemId
                    ? { ...it, mid: m.id, sku: m.sku, desc: m.desc, unit: m.unit, price: m.price, margin: m.margin }
                    : it)
                : s.quote.items;
              return { ...s, materials: [m, ...s.materials], quote: { ...s.quote, items } };
            });
            setNewMatModal(null);
            window.__matSavedToast = `Material agregado al catálogo: ${m.desc.slice(0,40)}`;
            setSavedToastAt(Date.now());
          }}
        />
      )}
      {rolePicker && (
        <RolePicker
          roles={state.roles}
          onClose={() => setRolePicker(null)}
          onPick={(r) => {
            updHH(rolePicker.hhId, { rid: r.id, role: r.role, rate: r.rate, social: r.social != null ? r.social : 40 });
            setRolePicker(null);
          }}
        />
      )}
      {clientPicker && typeof ClientPicker === "function" && (
        <ClientPicker
          clients={state.clients || []}
          onClose={() => setClientPicker(false)}
          onCreateNew={(prefill) => {
            // Load prefill into the current quote and close the picker;
            // the auto-save effect will persist it to the catalog.
            setClient({ name: prefill.name || "", rut: "", contact: "", email: "", phone: "", address: "" });
            setClientPicker(false);
          }}
          onPick={(c) => {
            setClient({
              name: c.name || "", rut: c.rut || "", contact: c.contact || "",
              email: c.email || "", phone: c.phone || "", address: c.address || "",
            });
            setClientPicker(false);
          }}
        />
      )}
      {editClientModal && typeof ClientModal === "function" && (
        <ClientModal
          initial={(() => {
            // Find this client in the catalog so we can edit the catalog entry,
            // not just the quote-local copy.
            const list = state.clients || [];
            const byRut  = q.client?.rut && list.find(x => window.normRut(x.rut) === window.normRut(q.client.rut));
            const byName = q.client?.name && list.find(x => window.normName(x.name) === window.normName(q.client.name));
            return byRut || byName || { ...q.client };
          })()}
          onClose={() => setEditClientModal(false)}
          onSave={(data) => {
            // Apply to BOTH the quote (so the user sees it immediately) and the catalog
            setState(s => {
              const next = { ...s, quote: { ...s.quote, client: {
                name: data.name || "", rut: data.rut || "", contact: data.contact || "",
                email: data.email || "", phone: data.phone || "", address: data.address || "",
              }}};
              if (data.id) {
                // Update existing catalog entry
                next.clients = (s.clients || []).map(x => x.id === data.id
                  ? { ...x, ...data, updatedAt: new Date().toISOString() }
                  : x);
              } else {
                // Upsert
                const { clients } = window.upsertClient(s.clients || [], data);
                next.clients = clients;
              }
              return next;
            });
            setEditClientModal(false);
            setClientSavedAt(Date.now());
          }}
        />
      )}
    </>
  );
}

function MatPicker({ materials, onClose, onPick, onCreateNew }) {
  const [q, setQ] = React.useState("");
  const [cat, setCat] = React.useState("Todas");
  const cats = ["Todas", ...Array.from(new Set(materials.map(m => m.cat))).sort()];
  const filtered = materials.filter(m => {
    if (cat !== "Todas" && m.cat !== cat) return false;
    if (!q.trim()) return true;
    const t = (m.sku + " " + m.desc + " " + m.cat).toLowerCase();
    return t.includes(q.toLowerCase());
  });
  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" onClick={e => e.stopPropagation()} style={{maxWidth:720,width:"100%"}}>
        <div className="modal-head">
          <h2>Buscar material</h2>
          <button className="btn ghost" onClick={onClose}>✕</button>
        </div>
        <div className="modal-body stack" style={{gap:12}}>
          <div className="row" style={{gap:10,flexWrap:"wrap"}}>
            <div className="row" style={{flex:1,minWidth:200,gap:8,padding:"8px 12px",border:"1px solid var(--line-strong)",borderRadius:8}}>
              <Icon.search size={16} />
              <input value={q} onChange={e=>setQ(e.target.value)} autoFocus
                     placeholder="Buscar por SKU, descripción…"
                     style={{border:0,background:"transparent",flex:1,outline:"none",fontSize:15}} />
            </div>
            <select className="btn" value={cat} onChange={e=>setCat(e.target.value)} style={{appearance:"auto"}}>
              {cats.map(c => <option key={c}>{c}</option>)}
            </select>
            {onCreateNew && (
              <button className="btn primary" onClick={() => onCreateNew({ desc: q })} title="Crear nuevo material en el catálogo">
                <Icon.plus /> Nuevo material
              </button>
            )}
            <span className="muted" style={{fontSize:12,alignSelf:"center"}}>{filtered.length} resultados</span>
          </div>
          <div style={{maxHeight:"55vh",overflow:"auto",border:"1px solid var(--line)",borderRadius:8}}>
            {filtered.length === 0 ? (
              <div className="empty">
                <div className="ico">∅</div>
                Sin resultados
                {onCreateNew && (
                  <div style={{marginTop:12}}>
                    <button className="btn primary sm" onClick={() => onCreateNew({ desc: q })}>
                      <Icon.plus /> Crear «nuevo material» {q ? `con "${q.slice(0,30)}"` : ""}
                    </button>
                  </div>
                )}
              </div>
            ) : filtered.map(m => (
              <div key={m.id} className="picker-row" onClick={() => onPick(m)}>
                <div style={{flex:1,minWidth:0}}>
                  <div style={{fontWeight:600,fontSize:14,whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"}}>{m.desc}</div>
                  <div style={{fontSize:11,color:"var(--muted)",marginTop:2}} className="mono">{m.sku} · {m.cat} · {m.unit}</div>
                </div>
                <div className="num" style={{fontWeight:700,fontSize:14,minWidth:90,textAlign:"right"}}>{clp(m.price)}</div>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

function RolePicker({ roles, onClose, onPick }) {
  const [q, setQ] = React.useState("");
  const filtered = roles.filter(r => !q.trim() || r.role.toLowerCase().includes(q.toLowerCase()));
  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" onClick={e => e.stopPropagation()} style={{maxWidth:560,width:"100%"}}>
        <div className="modal-head">
          <h2>Buscar perfil HH</h2>
          <button className="btn ghost" onClick={onClose}>✕</button>
        </div>
        <div className="modal-body stack" style={{gap:12}}>
          <div className="row" style={{gap:8,padding:"8px 12px",border:"1px solid var(--line-strong)",borderRadius:8}}>
            <Icon.search size={16} />
            <input value={q} onChange={e=>setQ(e.target.value)} autoFocus
                   placeholder="Buscar perfil por nombre…"
                   style={{border:0,background:"transparent",flex:1,outline:"none",fontSize:15}} />
          </div>
          <div style={{maxHeight:"55vh",overflow:"auto",border:"1px solid var(--line)",borderRadius:8}}>
            {filtered.length === 0 ? (
              <div className="empty"><div className="ico">∅</div>Sin resultados</div>
            ) : filtered.map(r => {
              const social = +r.social || 0;
              const withSocial = (+r.rate || 0) * (1 + social / 100);
              return (
                <div key={r.id} className="picker-row" onClick={() => onPick(r)}>
                  <div style={{flex:1,minWidth:0}}>
                    <div style={{fontWeight:600,fontSize:14}}>{r.role}</div>
                    <div style={{fontSize:11,color:"var(--muted)",marginTop:2}}>{r.unit || "HH"} · Leyes soc. {social}%</div>
                  </div>
                  <div style={{textAlign:"right",minWidth:120}}>
                    <div className="num" style={{fontWeight:700,fontSize:14}}>{clp(r.rate)}</div>
                    <div className="muted" style={{fontSize:10.5,marginTop:2}}>c/leyes {clp(withSocial)}</div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { QuoteView, MatPicker, RolePicker });
