/* =====================================================================
   App — Componente raiz del cotizador
   Orquesta:
     - State global (D, view, modal, edt, etc.)
     - Helpers (up, openNew, openEd, saveForm, nuevaCot, cotAPedido, ...)
     - Carga/autosave via Api
     - Pasa ctx `app` a todas las paginas (PageDashboard, PageCotizaciones, ...)
     - Renderiza sidebar, topbar, modal de email, vista previa PDF
   ===================================================================== */

function App() {

  // ============== STATE ==============
  const [D, setD]                 = useState(INIT);
  const [view, setView]           = useState("dashboard");
  const [modal, setModal]         = useState(null);
  const [edt, setEdt]             = useState(null);
  const [search, setSearch]       = useState("");

  // Filtros por vista
  const [cotFEstado, setCotFEstado]   = useState("");
  const [cotFCliente, setCotFCliente] = useState("");
  const [catFTipo, setCatFTipo]       = useState("");
  const [catFTextil, setCatFTextil]   = useState("");

  // Edicion de usuarios
  const [eu, setEu] = useState(null);
  const [nu, setNu] = useState(null);

  // Dashboard filters
  const [dDesde, setDDesde]       = useState("");
  const [dHasta, setDHasta]       = useState("");
  const [filtroEst, setFiltroEst] = useState("todos");

  // Maquila / Plantillas / Pago
  const [editMq, setEditMq]   = useState(null);
  const [ep, setEp]           = useState(null);
  const [newPago, setNewPago] = useState("");
  const [stab, setStab]       = useState(0);

  // App bootstrap + autosave
  const [ok, setOk]       = useState(false);
  const [saved, setSaved] = useState("");
  const sr = useRef(null);

  // PDF preview
  const [pdfCot, setPdfCot]               = useState(null);
  const [pdfKind, setPdfKind]             = useState("cot"); // "cot" | "ped"
  const [pdfPaperSize, setPdfPaperSize]   = useState("letter");
  const pdfHtml = useMemo(() => {
    if (!pdfCot) return null;
    return pdfKind === "ped"
      ? PdfBuilder.buildPedido(pdfCot, D, { paperSize: pdfPaperSize })
      : PdfBuilder.buildCotizacion(pdfCot, D, { paperSize: pdfPaperSize });
  }, [pdfCot, pdfKind, pdfPaperSize, D]);

  // Email + sesion
  const [emailModal, setEmailModal] = useState(null);
  // Login desactivado en SPA — auto-admin (Root maneja login real con backend)
  const [session, setSession]       = useState({ id: 1, nombre: "Juan Carlos Velasco", nivel: 3, verCostos: true });
  const [loginErr, setLoginErr]     = useState("");

  // Convertir cotizacion → pedido
  const [convertCot, setConvertCot]     = useState(null);
  const [convertTipo, setConvertTipo]   = useState(TIPOS_NEGOCIO[0]);

  // Bulk import — Textiles / Insumos / Proveedores
  const [showBulk, setShowBulk]             = useState(false);
  const [bulkText, setBulkText]             = useState("");
  const [bulkMsg, setBulkMsg]               = useState("");
  const [showBulkIns, setShowBulkIns]       = useState(false);
  const [bulkTextIns, setBulkTextIns]       = useState("");
  const [showBulkProv, setShowBulkProv]     = useState(false);
  const [bulkTextProv, setBulkTextProv]     = useState("");

  // ============== AUTH HELPERS (delegan en Permissions) ==============
  const puede      = (accion) => Permissions.can(session, accion);
  const nivelLabel = Permissions.label;
  const nivelColor = Permissions.color;
  const doLogin    = (correo, clave) => {
    const user = (D.usuarios || []).find(u => u.correo === correo && u.clave === clave && u.estado === "activo");
    if (user) { setSession(user); setLoginErr(""); }
    else      { setLoginErr("Correo o contraseña incorrectos"); }
  };

  // ============== EMAIL / PDF HELPERS ==============
  const verPDF    = (cot) => { setPdfKind("cot"); setPdfCot(cot); };
  const verPedPDF = (ped) => { setPdfKind("ped"); setPdfCot(ped); };
  const openEmail = (tipo, doc) => {
    const cli = D.clientes.find(c => c.id === doc.clienteId) || {};
    const num = doc.numero || "—";
    setEmailModal({
      tipo, numero: num, data: doc,
      para:    cli.correo || doc.correo || "",
      asunto:  `${tipo === "cot" ? "Cotización" : "Pedido"} ${num} — Veliantex S.A.S.`,
      mensaje: `Cordial saludo ${cli.contacto || cli.razon || ""},\n\nAdjunto encontrará ${tipo === "cot" ? "la cotización" : "el pedido"} ${num}.\n\nQuedamos atentos a sus comentarios.\n\nJuan Carlos Velasco Lian\nVeliantex S.A.S.\n(+57) 316 4489436`
    });
  };

  // ============== EFFECTS — load + autosave ==============
  useEffect(() => {
    Api.load().then(s => {
      if (s) {
        Object.keys(INIT).forEach(k => { if (!(k in s)) s[k] = INIT[k]; });
        setD(s);
      }
      setOk(true);
    });
  }, []);

  useEffect(() => {
    if (!ok) return;
    if (sr.current) clearTimeout(sr.current);
    sr.current = setTimeout(() => {
      Api.save(D).then(() => {
        setSaved("✓"); setTimeout(() => setSaved(""), 2000);
      });
    }, 1500);
    return () => { if (sr.current) clearTimeout(sr.current); };
  }, [D, ok]);

  // ============== CRUD HELPERS ==============
  const up        = (k, v)    => setD(d => ({ ...d, [k]: v }));
  const filt      = arr       => { if (!search) return arr; const s = search.toLowerCase(); return arr.filter(x => JSON.stringify(x).toLowerCase().includes(s)); };
  const del       = (t, id)   => up(t, D[t].filter(x => x.id !== id));
  const openNew   = (t, tpl)  => { setEdt({ ...tpl, id: 0, _t: t }); setModal("form"); };
  const openEd    = (t, item) => { setEdt({ ...item, _t: t }); setModal("form"); };
  const saveForm  = (directItem) => {
    const ei = directItem || edt;
    if (!ei) return;
    const t = ei._t;
    const { _t, ...item } = ei;
    if (item.id === 0) { item.id = nid(D[t]); up(t, [...D[t], item]); }
    else                up(t, D[t].map(x => x.id === item.id ? item : x));
    setModal(null); setEdt(null);
  };

  // ============== COTIZACION HELPERS ==============
  const cotNombre = cn => cn || "Sin cliente";

  const genCotNum = (clienteId, clienteNombre) => {
    const year         = new Date().getFullYear();
    const inicial      = (clienteNombre || "X").charAt(0).toUpperCase();
    const cotCliente   = D.cotizaciones.filter(c => c.clienteId === clienteId);
    const seq          = String(cotCliente.length + 1).padStart(3, "0");
    return `${inicial}-${seq}-${year}`;
  };

  const nuevaCot = () => {
    const year = new Date().getFullYear();
    const seq  = String(D.cotizaciones.length + 1).padStart(3, "0");
    const c = {
      id: nid(D.cotizaciones), numero: `COT-${seq}-${year}`, nombreCot: "", fecha: hoy(),
      vigencia: "15 días", comercial: "", clienteId: null, clienteNombre: "", proyecto: "",
      flete: "No incluido", metodoPago: D.metodosPago[0] || "", diasEntrega: 30, garantiaMeses: 0,
      estado: "Borrador", razonNo: "", obsInt: "", obsExt: "", items: [], margenGlobal: 35
    };
    up("cotizaciones", [...D.cotizaciones, c]);
    setView("cotizaciones"); setEdt(c); setModal("cotizador");
  };

  const saveCot = c => {
    up("cotizaciones", D.cotizaciones.map(x => x.id === c.id ? c : x));
    setModal(null); setEdt(null);
  };

  const cotAPedido = (cot, tipoNegocio) => {
    const cl = D.clientes.find(c => c.id === cot.clienteId) || {};
    const tallasObj = (D.tallas || []).reduce((a, t) => ({ ...a, [t]: 0 }), {});
    const ped = {
      id: nid(D.pedidos),
      numero: `PED-${new Date().getFullYear()}-${String(D.pedidos.length + 1).padStart(3, "0")}`,
      nombrePed: `${cl.razon || cot.clienteNombre || "Pedido"}-${hoy()}`,
      fecha: hoy(), cotId: cot.id, cotNum: cot.numero,
      clienteId: cot.clienteId, clienteNombre: cot.clienteNombre || cl.razon || "",
      contacto: cl.contacto || "", telContacto: cl.tel || "",
      dirEntrega: cl.dirEntrega || "", dirFactura: cl.dirFactura || "",
      contactoRecibe: "", telRecibe: "", fechaCompromiso: "", responsable: "",
      ocCliente: "", tipoNegocio: tipoNegocio || "",
      items: (cot.items || []).map(it => ({
        ...it,
        tallasDetalle: { ...tallasObj }, tallasCustom: [],
        molde: "", patronista: "",
        provCorte: "", provConf: "", provEst: "", provEmp: "",
        renderUrl: "", empaqueD: it.empaque || "Individual",
        insumosD: (it.insumosItems || it.insumosIds || []).map(x => {
          const id  = typeof x === "object" ? x.id : x;
          const qty = typeof x === "object" ? x.qty : 1;
          const ins = D.insumos.find(z => z.id === id);
          return ins ? `${ins.nombre}${qty > 1 ? " ×" + qty : ""}` : "";
        }).filter(Boolean).join(", "),
        notas: ""
      })),
      estado: "Pendiente", obs: cot.obsExt || ""
    };
    up("pedidos", [...D.pedidos, ped]);
    up("cotizaciones", D.cotizaciones.map(c => c.id === cot.id ? { ...c, estado: "Pedido realizado" } : c));
    setConvertCot(null);
    setSaved("✓ Pedido creado"); setTimeout(() => setSaved(""), 3000);
  };

  // Tabla generica con encabezado y empty-state
  const tbl = (cols, rows, acts) => (
    <div style={{ overflowX: "auto" }}>
      <table style={{ width: "100%", borderCollapse: "collapse" }}>
        <thead><tr>{cols.map(c => <th key={c.l} style={{ ...S.th, ...(c.a ? { textAlign: c.a } : {}) }}>{c.l}</th>)}{acts && <th style={S.th}></th>}</tr></thead>
        <tbody>
          {rows.length === 0
            ? <tr><td colSpan={cols.length + (acts ? 1 : 0)} style={{ textAlign:"center", padding:36, color:"#9ca3af", fontSize:12 }}>Sin registros</td></tr>
            : rows}
        </tbody>
      </table>
    </div>
  );

  // ============== BULK IMPORT HELPERS ==============
  const splitLine = (line) => {
    const l = line.replace(/^﻿/, "");
    if (l.split("\t").length > 1) return l.split("\t");
    if (l.split(";").length  > 1) return l.split(";");
    return l.split(",");
  };

  const doBulkImport = () => {
    const lines = bulkText.trim().split("\n").filter(l => l.trim() && !l.startsWith(" "));
    const nuevos = []; let nextCode = nid(D.textiles);
    const p = (s) => (s || "").trim();
    const n = (s) => parseFloat((s || "0").trim().replace(/[^0-9.]/g, "")) || 0;
    lines.forEach(line => {
      const c = splitLine(line);
      if (c.length >= 2 && p(c[1])) {
        nuevos.push({
          id: nextCode++, codigo: p(c[0]) || `TX-${String(nextCode).padStart(3,"0")}`,
          nombre: p(c[1]), proveedor: p(c[2]), composicion: p(c[3]),
          gramaje: n(c[4]), ancho: n(c[5]) || 150, unidad: p(c[6]) || "Metro",
          precio: n(c[7]), iva: n(c[8]) || 19,
          dctoPP: n(c[9]), dctoVol: n(c[10]),
          volMin: n(c[11]), diasAbast: n(c[12]) || 5,
          colores: p(c[13]), ref: p(c[14]),
          estado: p(c[15]) || "Activo", obs: ""
        });
      }
    });
    if (nuevos.length > 0) {
      up("textiles", [...D.textiles, ...nuevos]);
      setBulkText(""); setShowBulk(false);
      setSaved(`✓ ${nuevos.length} textiles importados`); setTimeout(() => setSaved(""), 3000);
    } else {
      setBulkMsg("No se detectaron datos válidos. Verifica el formato."); setTimeout(() => setBulkMsg(""), 4000);
    }
  };

  const doBulkImportIns = () => {
    const lines = bulkTextIns.trim().split("\n").filter(l => l.trim() && !l.startsWith(" "));
    const nuevos = []; let nextCode = nid(D.insumos);
    const p = (s) => (s || "").trim();
    const n = (s) => parseFloat((s || "0").trim().replace(/[^0-9.]/g, "")) || 0;
    lines.forEach(line => {
      const c = splitLine(line);
      if (c.length >= 2 && p(c[1])) {
        nuevos.push({
          id: nextCode++, codigo: p(c[0]) || `IN-${String(nextCode).padStart(3, "0")}`,
          nombre: p(c[1]), cat: p(c[2]) || "General", unidad: p(c[3]) || "Unidad",
          costo: n(c[4]), iva: n(c[5]) || 19,
          proveedor: p(c[6]), variante: p(c[7]),
          consumo: 1, obs: "", estado: "Activo"
        });
      }
    });
    if (nuevos.length > 0) {
      up("insumos", [...D.insumos, ...nuevos]);
      setBulkTextIns(""); setShowBulkIns(false);
      setSaved(`✓ ${nuevos.length} insumos importados`); setTimeout(() => setSaved(""), 3000);
    } else {
      setBulkMsg("No se detectaron datos válidos. Verifica el formato."); setTimeout(() => setBulkMsg(""), 4000);
    }
  };

  const doBulkImportProv = () => {
    const lines = bulkTextProv.trim().split("\n").filter(l => l.trim() && !l.startsWith(" "));
    const nuevos = []; let nextCode = nid(D.proveedores);
    const p = (s) => (s || "").trim();
    lines.forEach(line => {
      const c = splitLine(line);
      if (c.length >= 1 && p(c[0])) {
        nuevos.push({
          id: nextCode++, nombre: p(c[0]), nit: p(c[1]),
          contacto: p(c[2]), direccion: p(c[3]), ciudad: p(c[4]) || "Cali",
          email: p(c[5]), celular: p(c[6]), tipo: p(c[7]) || "Textil",
          estado: "Activo"
        });
      }
    });
    if (nuevos.length > 0) {
      up("proveedores", [...D.proveedores, ...nuevos]);
      setBulkTextProv(""); setShowBulkProv(false);
      setSaved(`✓ ${nuevos.length} proveedores importados`); setTimeout(() => setSaved(""), 3000);
    } else {
      setBulkMsg("No se detectaron datos válidos. Verifica el formato."); setTimeout(() => setBulkMsg(""), 4000);
    }
  };

  // ============== MENU ==============
  const menu = [
    { k: "dashboard",    ic: "chart",    l: "Dashboard" },
    { k: "textiles",     ic: "box",      l: "Textiles" },
    { k: "insumos",      ic: "box",      l: "Insumos" },
    { k: "maquila",      ic: "factory",  l: "Servicios Maquila" },
    { k: "tecnicas",     ic: "scissors", l: "Técnicas Estampado" },
    { k: "prendas",      ic: "box",      l: "Tipos de Prenda" },
    { k: "moldes",       ic: "factory",  l: "Moldería" },
    { k: "clientes",     ic: "users",    l: "Clientes" },
    { k: "proveedores",  ic: "truck",    l: "Proveedores" },
    { k: "plantillas",   ic: "tag",      l: "Plantillas Cargos" },
    { k: "catalogo",     ic: "box",      l: "Catálogo Productos" },
    { k: "cotizaciones", ic: "doc",      l: "Cotizaciones" },
    { k: "pedidos",      ic: "cart",     l: "Pedidos" },
  ];
  const menuFull = puede("usuarios") ? [...menu, { k: "usuarios", ic: "users", l: "Usuarios y Roles" }] : menu;

  // ============== MASTER CONFIGS (mc) — usado por MPg ==============
  const mc = {
    textiles:    { title: "Textiles",    tpl: { codigo:"", nombre:"", proveedor:"", composicion:"", gramaje:0, ancho:150, unidad:"Metro", precio:0, iva:19, dctoPP:0, dctoVol:0, volMin:0, diasAbast:5, colores:"", ref:"", obs:"", estado:"Activo" },
                   cols: [{l:"Código"},{l:"Nombre"},{l:"Precio",a:"right"},{l:"Estado"}],
                   rr: t => <tr key={t.id}><td style={S.td}><strong>{t.codigo}</strong></td><td style={S.td}>{t.nombre}<br /><span style={{fontSize:10, color:"#9ca3af"}}>{t.proveedor} · {t.gramaje}g/m² · {t.ancho}cm</span></td><td style={{...S.td, textAlign:"right", fontWeight:600}}>{fmt(t.precio)}</td><td style={S.td}><span style={S.badge(t.estado === "Activo" ? "green" : "red")}>{t.estado}</span></td><td style={S.td}><div style={{display:"flex", gap:3}}><button style={S.btn2} onClick={() => openEd("textiles", t)}><Ic name="edit" size={12} /></button><button style={S.btnD} onClick={() => del("textiles", t.id)}><Ic name="trash" size={12} /></button></div></td></tr> },
    insumos:     { title: "Insumos",     tpl: { codigo:"", nombre:"", cat:"General", unidad:"Unidad", costo:0, iva:19, proveedor:"", consumo:1, variante:"", obs:"" },
                   cols: [{l:"Código"},{l:"Nombre"},{l:"Categoría"},{l:"Costo",a:"right"},{l:"Proveedor"}],
                   rr: i => <tr key={i.id}><td style={S.td}><strong>{i.codigo}</strong></td><td style={S.td}>{i.nombre}</td><td style={S.td}><span style={S.badge("blue")}>{i.cat}</span></td><td style={{...S.td, textAlign:"right"}}>{fmt(i.costo)}/{i.unidad}</td><td style={S.td}>{i.proveedor || "—"}</td><td style={S.td}><div style={{display:"flex", gap:3}}><button style={S.btn2} onClick={() => openEd("insumos", i)}><Ic name="edit" size={12} /></button><button style={S.btnD} onClick={() => del("insumos", i.id)}><Ic name="trash" size={12} /></button></div></td></tr> },
    tecnicas:    { title: "Técnicas de Estampado", type: "tecnicas", tpl: { nombre:"", unidadCobro:"cm²", costoBase:0, proveedor:"", desc:"", estado:"Activo" },
                   cols: [{l:"Nombre"},{l:"Unidad"},{l:"Costo Base",a:"right"},{l:"Proveedor"},{l:"Estado"}],
                   rr: t => <tr key={t.id}><td style={S.td}><strong>{t.nombre}</strong><br /><span style={{fontSize:10, color:"#9ca3af"}}>{t.desc}</span></td><td style={S.td}><span style={S.badge("blue")}>{t.unidadCobro}</span></td><td style={{...S.td, textAlign:"right", fontWeight:600}}>{fmt(t.costoBase)}/{t.unidadCobro}</td><td style={S.td}>{t.proveedor || "—"}</td><td style={S.td}><span style={S.badge(t.estado === "Activo" ? "green" : "red")}>{t.estado}</span></td><td style={S.td}><div style={{display:"flex", gap:3}}><button style={S.btn2} onClick={() => openEd("tecnicas", t)}><Ic name="edit" size={12} /></button><button style={S.btnD} onClick={() => del("tecnicas", t.id)}><Ic name="trash" size={12} /></button></div></td></tr> },
    prendas:     { title: "Tipos de Prenda", type: "tiposPrenda", tpl: { codigo:"", nombre:"", cat:"Superior", desc:"", consumoDefault:0.65, insumosDefault:[], procesosDefault:{corte:1500, confeccion:6500, empaque:800}, estado:"Activo" },
                   cols: [{l:"Código"},{l:"Nombre"},{l:"Cat."},{l:"Consumo",a:"right"},{l:"Estado"}],
                   rr: p => <tr key={p.id}><td style={S.td}><strong>{p.codigo}</strong></td><td style={S.td}>{p.nombre}<br /><span style={{fontSize:10, color:"#9ca3af"}}>{p.desc}</span></td><td style={S.td}><span style={S.badge("blue")}>{p.cat}</span></td><td style={{...S.td, textAlign:"right"}}>{p.consumoDefault}m</td><td style={S.td}><span style={S.badge(p.estado === "Activo" ? "green" : "red")}>{p.estado}</span></td><td style={S.td}><div style={{display:"flex", gap:3}}><button style={S.btn2} onClick={() => openEd("tiposPrenda", p)}><Ic name="edit" size={12} /></button><button style={S.btnD} onClick={() => del("tiposPrenda", p.id)}><Ic name="trash" size={12} /></button></div></td></tr> },
    moldes:      { title: "Moldería",    tpl: { codigo:"", tipoPrenda:"", version:"v1", patronista:"", escala:"XS-XL", obs:"", estado:"Activo" },
                   cols: [{l:"Código"},{l:"Prenda"},{l:"Patronista"},{l:"Escala"},{l:"Estado"}],
                   rr: m => <tr key={m.id}><td style={S.td}><strong>{m.codigo}</strong></td><td style={S.td}>{m.tipoPrenda}</td><td style={S.td}>{m.patronista}</td><td style={S.td}>{m.escala}</td><td style={S.td}><span style={S.badge(m.estado === "Activo" ? "green" : "red")}>{m.estado}</span></td><td style={S.td}><div style={{display:"flex", gap:3}}><button style={S.btn2} onClick={() => openEd("moldes", m)}><Ic name="edit" size={12} /></button><button style={S.btnD} onClick={() => del("moldes", m.id)}><Ic name="trash" size={12} /></button></div></td></tr> },
    clientes:    { title: "Clientes",    tpl: { tipo:"Empresa", razon:"", nit:"", comercial:"", contacto:"", correo:"", tel:"", dir:"", ciudad:"Cali", dirFactura:"", dirEntrega:"", condiciones:"", obs:"", estado:"Activo" },
                   cols: [{l:"Razón Social"},{l:"NIT"},{l:"Contacto"},{l:"Ciudad"}],
                   rr: c => <tr key={c.id}><td style={S.td}><strong>{c.razon}</strong><br /><span style={{fontSize:10, color:"#9ca3af"}}>{c.tipo} · {c.comercial}</span></td><td style={S.td}>{c.nit}</td><td style={S.td}>{c.contacto}<br /><span style={{fontSize:10, color:"#6b7280"}}>{c.correo}</span></td><td style={S.td}>{c.ciudad}</td><td style={S.td}><div style={{display:"flex", gap:3}}><button style={S.btn2} onClick={() => openEd("clientes", c)}><Ic name="edit" size={12} /></button><button style={S.btnD} onClick={() => del("clientes", c.id)}><Ic name="trash" size={12} /></button></div></td></tr> },
    proveedores: { title: "Proveedores", tpl: { nombre:"", nit:"", contacto:"", direccion:"", ciudad:"Cali", email:"", celular:"", tipo:"Textil", estado:"Activo" },
                   cols: [{l:"Nombre"},{l:"NIT"},{l:"Contacto"},{l:"Celular"},{l:"Ciudad"},{l:"Tipo"}],
                   rr: p => <tr key={p.id}><td style={S.td}><strong>{p.nombre}</strong>{p.email && <div style={{fontSize:10, color:"#6b7280"}}>{p.email}</div>}</td><td style={S.td}>{p.nit || "—"}</td><td style={S.td}>{p.contacto || "—"}</td><td style={S.td}>{p.celular || "—"}</td><td style={S.td}>{p.ciudad}</td><td style={S.td}><span style={S.badge("blue")}>{p.tipo}</span></td><td style={S.td}><div style={{display:"flex", gap:3}}><button style={S.btn2} onClick={() => openEd("proveedores", p)}><Ic name="edit" size={12} /></button><button style={S.btnD} onClick={() => del("proveedores", p.id)}><Ic name="trash" size={12} /></button></div></td></tr> },
  };

  // ============== APP CONTEXT — pasado a las paginas ==============
  const app = {
    D, setD, view, setView, modal, setModal, edt, setEdt, search, setSearch,
    cotFEstado, setCotFEstado, cotFCliente, setCotFCliente,
    catFTipo, setCatFTipo, catFTextil, setCatFTextil,
    eu, setEu, nu, setNu,
    dDesde, setDDesde, dHasta, setDHasta, filtroEst, setFiltroEst,
    editMq, setEditMq, ep, setEp, newPago, setNewPago, stab, setStab,
    saved, setSaved, ok,
    pdfCot, setPdfCot, pdfKind, setPdfKind, pdfPaperSize, setPdfPaperSize, pdfHtml,
    emailModal, setEmailModal, session, setSession, loginErr, setLoginErr,
    convertCot, setConvertCot, convertTipo, setConvertTipo,
    up, filt, del, openNew, openEd, saveForm,
    cotNombre, genCotNum, nuevaCot, saveCot, cotAPedido,
    tbl, verPDF, verPedPDF, openEmail, doLogin,
    puede, nivelLabel, nivelColor,
    menu, menuFull,
    showBulk, setShowBulk, bulkText, setBulkText,
    showBulkIns, setShowBulkIns, bulkTextIns, setBulkTextIns,
    showBulkProv, setShowBulkProv, bulkTextProv, setBulkTextProv,
    bulkMsg, setBulkMsg,
    splitLine, doBulkImport, doBulkImportIns, doBulkImportProv,
    mc,
  };

  // ============== ROUTER — escoge la pagina segun `view` ==============
  const renderPage = () => {
    if (view === "dashboard")    return PgDash(app);
    if (view === "cotizaciones") return PgCot(app);
    if (view === "pedidos")      return PgPed(app);
    if (view === "plantillas")   return PgPl(app);
    if (view === "maquila")      return PgMaquila(app);
    if (view === "catalogo")     return PgCatalogo(app);
    if (view === "usuarios" && puede("usuarios")) return PgUsuarios(app);
    const cfg = mc[view];
    if (cfg) {
      const dt = cfg.type || view;
      const extra = puede("crear")
        ? (dt === "textiles"    ? <button style={S.btn2} onClick={() => setShowBulk(!showBulk)}><Ic name="download" size={12} /> Importar masivo</button>
         : dt === "insumos"     ? <button style={S.btn2} onClick={() => setShowBulkIns(!showBulkIns)}><Ic name="download" size={12} /> Importar masivo</button>
         : dt === "proveedores" ? <button style={S.btn2} onClick={() => setShowBulkProv(!showBulkProv)}><Ic name="download" size={12} /> Importar masivo</button>
         : null)
        : null;
      return MPg(app, { title: cfg.title, type: dt, tpl: cfg.tpl, cols: cfg.cols, rr: cfg.rr, extra });
    }
    return PgDash(app);
  };

  if (!ok) {
    return <div style={{ display:"flex", alignItems:"center", justifyContent:"center", height:"100vh", fontFamily:"Georgia,serif", color:"#0a2540", fontSize:16 }}>Cargando...</div>;
  }

  // ============== RENDER ==============
  return (
    <div style={S.app}>
      <link href="https://fonts.googleapis.com/css2?family=Libre+Franklin:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />

      {/* SIDEBAR */}
      <div style={S.sidebar}>
        <div style={{ padding:"16px 14px 10px", borderBottom:"1px solid rgba(255,255,255,0.08)" }}>
          <img src={LOGO} alt="V" style={{ width:"100%", borderRadius:5 }} />
          <div style={{ fontSize:8.5, color:"#8faabe", marginTop:5, textAlign:"center", letterSpacing:2, textTransform:"uppercase" }}>Cotización v5</div>
        </div>
        <div style={{ flex:1, padding:"6px 0" }}>
          {menuFull.map(m => (
            <div key={m.k} style={S.si(view === m.k)} onClick={() => {
              setView(m.k); setSearch(""); setCotFEstado(""); setCotFCliente("");
              setCatFTipo(""); setCatFTextil(""); setFiltroEst("todos");
              setEu(null); setNu(null); setEditMq(null); setEp(null); setNewPago(""); setStab(0);
            }}>
              <Ic name={m.ic} size={15} /><span>{m.l}</span>
            </div>
          ))}
        </div>
        {session && (
          <div style={{ padding:"8px 14px", borderTop:"1px solid rgba(255,255,255,0.08)" }}>
            <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center" }}>
              <div>
                <div style={{ fontSize:11, color:"#e8d5b7", fontWeight:600 }}>{session.nombre.split(" ")[0]}</div>
                <div style={{ fontSize:9, color:"#8faabe" }}>
                  <span style={{
                    padding:"1px 5px", borderRadius:3,
                    background: session.nivel >= 3 ? "rgba(239,68,68,0.2)" : session.nivel >= 2 ? "rgba(59,130,246,0.2)" : "rgba(255,255,255,0.1)",
                    color:      session.nivel >= 3 ? "#fca5a5"             : session.nivel >= 2 ? "#93c5fd"             : "#8faabe",
                    fontWeight:600
                  }}>{nivelLabel(session.nivel)}</span>
                </div>
              </div>
              <button style={{ background:"rgba(255,255,255,0.08)", border:"none", padding:"4px 8px", borderRadius:4, color:"#8faabe", fontSize:10, cursor:"pointer" }}
                      onClick={() => setSession(null)}>Salir</button>
            </div>
          </div>
        )}
        <div style={{ padding:10, borderTop:"1px solid rgba(255,255,255,0.08)", fontSize:9, color:"#6b8299", textAlign:"center" }}>
          Veliantex S.A.S.<br/>Vitality Sportswear
        </div>
      </div>

      {/* MAIN */}
      <div style={S.main}>
        <div style={S.topbar}>
          <div style={{ display:"flex", alignItems:"center", gap:10 }}>
            <span style={{ fontSize:15, fontWeight:700, color:"#0a2540", fontFamily:"Georgia,serif" }}>
              {menuFull.find(m => m.k === view)?.l || "Dashboard"}
            </span>
            {saved && <span style={{ fontSize:10.5, color:"#065f46", background:"#d1fae5", padding:"2px 7px", borderRadius:4 }}>{saved} Guardado</span>}
          </div>
          <div style={{ display:"flex", alignItems:"center", gap:10 }}>
            <input style={{ ...S.inp, width:180 }} placeholder="Buscar..." value={search} onChange={e => setSearch(e.target.value)} />
            {puede("crear") && <button style={S.btn} onClick={nuevaCot}><Ic name="plus" size={13} /> Cotización</button>}
          </div>
        </div>
        <div style={S.content}>{renderPage()}</div>
      </div>

      {/* MODALES */}
      {modal === "form"      && edt && <MForm edt={edt} setEdt={setEdt} setModal={setModal} D={D} saveForm={saveForm} />}
      {modal === "cotizador" && edt && <MCot  edt={edt} setD={setD} setModal={setModal} setSaved={setSaved} D={D} saveCot={saveCot} genCotNum={genCotNum} verPDF={verPDF} openEmail={openEmail} />}
      {modal === "pedido"    && edt && <MPed  edt={edt} setModal={setModal} setEdt={setEdt} verPedPDF={verPedPDF} D={D} up={up} openEmail={openEmail} />}

      {/* Conversion popup — tipo de negocio */}
      {convertCot && (
        <div style={S.modal} onMouseDown={e => { if (e.target === e.currentTarget) setConvertCot(null); }}>
          <div style={{ background:"#fff", borderRadius:14, padding:24, width:420, boxShadow:"0 12px 40px rgba(0,0,0,.2)", border:"2px solid #e8d5b7" }} onMouseDown={e => e.stopPropagation()}>
            <h3 style={{ margin:"0 0 4px", fontSize:16, color:"#0a2540", fontFamily:"Georgia,serif" }}>Aprobar cotización</h3>
            <div style={{ fontSize:11, color:"#6b7280", marginBottom:14 }}>COT-{convertCot.numero} · {convertCot.clienteNombre || "—"}</div>
            <F l="Tipo de negocio">
              <select style={{ ...S.sel, fontSize:13, padding:"10px 12px" }} value={convertTipo} onChange={e => setConvertTipo(e.target.value)}>
                {TIPOS_NEGOCIO.map(t => <option key={t} value={t}>{t}</option>)}
              </select>
            </F>
            <div style={{ fontSize:10, color:"#9ca3af", margin:"8px 0 14px", padding:"6px 10px", background:"#f0fdf4", borderRadius:5, border:"1px solid #bbf7d0" }}>
              La cotización se marcará como <strong style={{ color:"#065f46" }}>Pedido realizado</strong> y se creará un pedido nuevo.
            </div>
            <div style={{ display:"flex", gap:6 }}>
              <button style={{ ...S.btn, background:"#065f46", flex:1 }} onClick={() => cotAPedido(convertCot, convertTipo)}>Aprobar y crear pedido</button>
              <button style={S.btn2} onClick={() => setConvertCot(null)}>Cancelar</button>
            </div>
          </div>
        </div>
      )}

      {/* PDF preview */}
      {pdfHtml && (() => {
        const paper        = getPaper(pdfPaperSize);
        const previewHtml  = pdfHtml.replace(/<script>.*?<\/script>/g, "");
        const closePreview = () => { setPdfCot(null); };
        const descargarPDF = () => {
          const filename = (pdfCot ? pdfCot.numero || 'Documento' : 'Documento').replace(/\s+/g, '_') + '.pdf';
          const mm = (paper.margin.match(/[\d.]+/g) || [10, 10]).map(Number);
          const margin = mm.length === 1 ? [mm[0], mm[0], mm[0], mm[0]]
                       : mm.length === 2 ? [mm[0], mm[1], mm[0], mm[1]]
                       : mm.length === 3 ? [mm[0], mm[1], mm[2], mm[1]]
                       :                    [mm[0], mm[1], mm[2], mm[3]];
          const container = document.createElement('div');
          container.innerHTML  = pdfHtml;
          container.style.cssText = `position:fixed;left:-99999px;top:0;width:${paper.renderPx}px;background:#fff;`;
          document.body.appendChild(container);
          const target = container.querySelector('.pdf-page') || container;
          html2pdf().set({
            margin, filename,
            image:       { type:'jpeg', quality:0.98 },
            html2canvas: { scale:2, useCORS:true, backgroundColor:'#fff', width:paper.renderPx, windowWidth:paper.renderPx },
            jsPDF:       { unit:'mm', format:paper.jsFormat, orientation:'portrait' },
            pagebreak:   { mode:['css','legacy'], avoid:['tr','.firma-box','.footer'] }
          }).from(target).save().then(() => {
            document.body.removeChild(container);
          });
          closePreview();
          setSaved("✓ Descargando PDF..."); setTimeout(() => setSaved(""), 3000);
        };
        return (
          <div style={{ position:"fixed", inset:0, zIndex:2000, background:"#fff", overflow:"auto" }}>
            <div style={{ position:"sticky", top:0, zIndex:10, background:"#0a2540", padding:"10px 20px", display:"flex", justifyContent:"space-between", alignItems:"center", gap:12, flexWrap:"wrap" }}>
              <span style={{ color:"#e8d5b7", fontWeight:700, fontSize:13 }}>Vista previa</span>
              <div style={{ display:"flex", gap:8, alignItems:"center", flexWrap:"wrap" }}>
                <label style={{ color:"#e8d5b7", fontSize:11, fontWeight:600, display:"flex", alignItems:"center", gap:6 }}>
                  Tamaño:
                  <select value={pdfPaperSize} onChange={e => setPdfPaperSize(e.target.value)}
                          style={{ background:"#fff", color:"#0a2540", border:"none", borderRadius:5, padding:"6px 10px", fontSize:12, fontWeight:600, cursor:"pointer" }}>
                    {Object.entries(PAPER_SIZES).map(([k, p]) => <option key={k} value={k}>{p.label}</option>)}
                  </select>
                </label>
                <button style={{ background:"#e8d5b7", color:"#0a2540", border:"none", padding:"8px 20px", borderRadius:5, fontSize:12, fontWeight:700, cursor:"pointer" }} onClick={descargarPDF}>Descargar PDF</button>
                <button style={{ background:"#3b82f6", color:"#fff",     border:"none", padding:"8px 20px", borderRadius:5, fontSize:12, fontWeight:700, cursor:"pointer" }} onClick={() => { openEmail(pdfKind, pdfCot); closePreview(); }}>Enviar por correo</button>
                <button style={{ background:"rgba(255,255,255,0.15)", color:"#e8d5b7", border:"none", padding:"7px 14px", borderRadius:5, cursor:"pointer", fontSize:12 }} onClick={closePreview}>✕ Cerrar</button>
              </div>
            </div>
            <div dangerouslySetInnerHTML={{ __html: previewHtml }} style={{ maxWidth:paper.renderPx, margin:"0 auto", padding:"20px 0 40px" }} />
          </div>
        );
      })()}

      {/* Email modal */}
      {emailModal && (
        <div style={S.modal} onMouseDown={e => { if (e.target === e.currentTarget) setEmailModal(null); }}>
          <div style={{ ...S.mc, maxWidth:520 }} onMouseDown={e => e.stopPropagation()} onClick={e => e.stopPropagation()}>
            <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", marginBottom:14 }}>
              <h2 style={{ margin:0, color:"#0a2540", fontFamily:"Georgia,serif", fontSize:16 }}>
                Enviar {emailModal.tipo === "cot" ? "cotización" : "pedido"} por correo
              </h2>
              <button style={{ background:"none", border:"none", fontSize:18, cursor:"pointer", color:"#9ca3af" }} onClick={() => setEmailModal(null)}>✕</button>
            </div>
            <div style={{ fontSize:11, color:"#9ca3af", marginBottom:10, padding:"6px 10px", background:"#f0fdf4", borderRadius:5, border:"1px solid #bbf7d0" }}>
              Documento: <strong style={{ color:"#065f46" }}>{emailModal.numero}</strong>
            </div>
            <F l="Para (correo del cliente)"><input style={S.inp} value={emailModal.para}    onChange={e => setEmailModal({ ...emailModal, para:    e.target.value })} placeholder="correo@cliente.com" /></F>
            <F l="Asunto">                  <input style={S.inp} value={emailModal.asunto}  onChange={e => setEmailModal({ ...emailModal, asunto:  e.target.value })} /></F>
            <F l="Mensaje">              <textarea style={{ ...S.inp, minHeight:120, fontFamily:"inherit", fontSize:11 }} value={emailModal.mensaje} onChange={e => setEmailModal({ ...emailModal, mensaje: e.target.value })} /></F>
            <div style={{ display:"flex", gap:6, marginTop:10 }}>
              <button style={{ ...S.btn, background:"#1e40af", color:"#fff" }} onClick={async () => {
                try {
                  setSaved("Enviando...");
                  const pdfData = emailModal.data
                    ? (emailModal.tipo === "cot"
                        ? PdfBuilder.buildCotizacion(emailModal.data, D, { paperSize: pdfPaperSize })
                        : PdfBuilder.buildPedido(emailModal.data, D, { paperSize: pdfPaperSize }))
                    : "";
                  await Api.sendEmail({
                    para: emailModal.para, asunto: emailModal.asunto,
                    mensaje: emailModal.mensaje, html: pdfData
                  });
                  setSaved("✓ Correo enviado"); setTimeout(() => setSaved(""), 4000);
                  setEmailModal(null);
                } catch (err) {
                  setSaved("✗ " + err.message); setTimeout(() => setSaved(""), 6000);
                }
              }}>Enviar correo</button>
              <button style={S.btn2} onClick={() => setEmailModal(null)}>Cancelar</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ── Exports a global scope (Babel standalone aisla cada <script>) ──
window.App = App;
