// contract-new.jsx — interactive "create contract" modal (quick-action target).
function addMonths(dateStr, n){
  const d = new Date(dateStr || TODAY); d.setMonth(d.getMonth() + n);
  return d.toISOString().slice(0, 10);
}

function NewContractModal({ onClose, editing, prefill }){
  const p = usePortal();
  const { t, lang } = useLang();
  const toast = useToast();
  const [f, setF] = React.useState(editing ? { direction:editing.direction || 'sell', contractNo:editing.contractNo || '', category:editing.category, signDate:editing.signDate, customer:editing.customer, rep:editing.rep || '', termType:editing.termType, startDate:editing.startDate || TODAY, endDate:editing.endDate || addMonths(editing.startDate || TODAY, 12), remindBefore:editing.remindBefore || 30, status:editing.status || 'active' } : { direction:(prefill && prefill.direction) || 'sell', contractNo:'', category:'mua-ban', signDate:TODAY, customer:(prefill && (prefill.customer || prefill.vendor)) || (prefill && prefill.direction === 'buy' ? '' : (p.customers[0] ? p.customers[0].code : '')), rep:'', termType:'once', startDate:TODAY, endDate:addMonths(TODAY, 12), remindBefore:30, status:'active' });
  // Prefill 1 hạng mục khi tạo HĐ mua từ cảnh báo định mức (Kho → Cảnh báo → Tạo HĐ mua).
  const prefItem = (!editing && prefill && prefill.item) ? (p.products || []).find(pr => pr.code === prefill.item) : null;
  const [items, setItems] = React.useState(
    // Giữ đủ field phụ khi sửa: detail/showDetail (mô tả chi tiết) + acceptDetail (Part/Serial từ biên bản nghiệm thu).
    editing && editing.items && editing.items.length ? editing.items.map(it => ({ name:it.name, unit:it.unit, qty:it.qty, price:it.price, vat:it.vat, detail:it.detail || '', showDetail:!!it.showDetail, acceptDetail:it.acceptDetail || '' }))
    : prefItem ? [{ name:prefItem.name, unit:prefItem.unit || 'gói', qty:+(prefill.qty) || 1, price:(window.productCost && productCost(prefItem)) || productPrice(prefItem) || 0, vat:prefItem.vat || 8, detail:prefItem.desc || '', showDetail:false }]
    : [{ name:'', unit:'gói', qty:1, price:0, vat:8, detail:'', showDetail:false }]);
  const [schedule, setSchedule] = React.useState(editing && editing.schedule && editing.schedule.length ? editing.schedule.map(s => ({ no:s.no, amount:s.amount, dueDate:s.dueDate, condition:s.condition, paid:s.paid, paidDate:s.paidDate })) : [{ no:1, amount:0, dueDate:TODAY, condition:lang === 'vi' ? 'Thanh toán khi ký' : 'On signing' }]);
  const [nInst, setNInst] = React.useState(2);
  // Chu kỳ thanh toán (HĐ kỳ hạn — thuê dịch vụ): tháng/quý/6T/12T → sinh lịch từ start→end.
  const [cycle, setCycle] = React.useState((editing && editing.billingCycle) || 'once');
  const [addProdOpen, setAddProdOpen] = React.useState(false);   // mở form Sản phẩm đầy đủ ngay trong form HĐ
  // Uỷ quyền của người đại diện ĐỐI TÁC (riêng từng HĐ) — lưu trong docOverrides.partyAuth; render ở khối Bên A/Bên B.
  const initPartyAuth = (editing && editing.docOverrides && editing.docOverrides.partyAuth) || null;
  const [repAuth, setRepAuth] = React.useState({ auth:!!initPartyAuth, no:(initPartyAuth && initPartyAuth.no) || '', date:(initPartyAuth && initPartyAuth.date) || '' });
  const set = (k, v) => setF(s => ({ ...s, [k]: v }));
  // Hợp đồng cũ (ký năm trước) → mã nội bộ suy theo NĂM KÝ (HD-2025-xxx), mở thêm chọn trạng thái + ghi mốc bản đầu theo ngày ký.
  const isOld = (f.signDate || '').slice(0, 4) < TODAY.slice(0, 4);
  const code = React.useMemo(() => editing ? editing.code : genContractCode(p.contracts, (f.signDate || TODAY).slice(0, 4)), [editing, f.signDate, p.contracts]);

  const tot = items.reduce((acc, it) => { const line = (+it.qty || 0) * (+it.price || 0); acc.sub += line; acc.vat += line * (+it.vat || 0) / 100; return acc; }, { sub:0, vat:0 });
  const total = tot.sub + tot.vat;

  // Số hợp đồng: mua = nhập tay (f.contractNo); bán = tự cấp theo cấu hình (app_settings.contractNoFormat),
  // nhưng CHO PHÉP sửa tay (vd nhập hợp đồng cũ): f.contractNo có giá trị → dùng giá trị đó (override).
  const khShort = (window.CustomerStore && (CustomerStore.byCode(f.customer) || {}).shortName) || f.customer || '';
  const autoContractNo = formatContractNo(p.appSettings.contractNoFormat, { date:f.signDate, kh:khShort, seq:editing ? null : (p.contracts.filter(c => contractDir(c) === 'sell').length + 1) });
  const contractNoVal = f.direction === 'buy' ? f.contractNo : ((f.contractNo || '').trim() ? f.contractNo : autoContractNo);

  const upItem = (i, k, v) => setItems(s => s.map((it, j) => j === i ? { ...it, [k]:v } : it));
  const addItem = () => setItems(s => [...s, { name:'', unit:'gói', qty:1, price:0, vat:8, detail:'', showDetail:false }]);
  const rmItem = (i) => setItems(s => s.length > 1 ? s.filter((_, j) => j !== i) : s);
  // Chọn từ danh mục Sản phẩm/Dịch vụ → tự điền ĐVT, giá, VAT + nạp sẵn "chi tiết" (mô tả SP) như form báo giá.
  // Giá theo CHIỀU hợp đồng: bán → giá bán mới nhất; mua → GIÁ MUA (giá vốn) làm mốc, sửa theo giá NCC chào.
  const products = p.products || [];
  const priceOf = (prod) => f.direction === 'buy' ? ((window.productCost && productCost(prod)) || 0) : productPrice(prod);
  const onItemName = (i, v) => {
    const prod = products.find(pr => pr.name === v);
    if (prod) setItems(s => s.map((it, j) => j === i ? { ...it, name:v, unit:prod.unit, price:priceOf(prod), vat:prod.vat, detail:prod.desc || it.detail || '' } : it));
    else upItem(i, 'name', v);
  };
  // Tích "Hiển thị chi tiết" → bật hiện; chưa có nội dung thì tự nạp từ mô tả sản phẩm (sửa được sau).
  const toggleDetail = (i) => setItems(s => s.map((it, j) => {
    if (j !== i) return it;
    const show = !it.showDetail; let detail = it.detail || '';
    if (show && !detail) { const prod = products.find(pr => pr.name === it.name); detail = (prod && prod.desc) || ''; }
    return { ...it, showDetail:show, detail };
  }));
  // Tạo SP mới ngay trong form HĐ (nút "Tạo SP mới") → SP vừa tạo điền vào dòng trống cuối, hoặc thêm dòng mới.
  const addItemFromProduct = (prod) => {
    const line = { name:prod.name, unit:prod.unit || 'gói', qty:1, price:priceOf(prod), vat:(prod.vat != null ? prod.vat : 8), detail:prod.desc || '', showDetail:false };
    setItems(s => {
      const last = s[s.length - 1];
      if (last && !(last.name || '').trim()) return s.map((it, j) => j === s.length - 1 ? line : it);
      return [...s, line];
    });
  };

  const genSchedule = () => {
    const n = Math.max(1, Math.min(12, +nInst || 1));
    const base = Math.floor(total / n / 1000) * 1000;
    const rows = [];
    for (let i = 0; i < n; i++){
      rows.push({ no:i + 1, amount:i === n - 1 ? total - base * (n - 1) : base, dueDate:addMonths(f.signDate, i), condition:i === 0 ? (lang === 'vi' ? 'Tạm ứng khi ký' : 'On signing') : (lang === 'vi' ? 'Đợt ' + (i + 1) : 'Installment ' + (i + 1)) });
    }
    setSchedule(rows);
  };
  // Sinh lịch theo CHU KỲ (HĐ kỳ hạn): các đợt đầu-mỗi-kỳ từ ngày bắt đầu → kết thúc, chia đều từ tổng.
  const genByCycle = () => {
    const rows = genCycleInstallments(cycle, f.startDate, f.endDate, total, 1);
    if (!rows.length) { toast(lang === 'vi' ? 'Chọn chu kỳ và kiểm tra ngày bắt đầu/kết thúc' : 'Pick a cycle and check start/end dates', 'error'); return; }
    setSchedule(rows);
  };
  // Sửa SỐ TIỀN một đợt (không phải đợt cuối) → đợt CUỐI (nếu chưa thu) tự nhận phần còn lại = tổng − các đợt trước.
  const upSch = (i, k, v) => setSchedule(list => {
    let next = list.map((r, j) => j === i ? { ...r, [k]:v } : r);
    const last = next.length - 1;
    if (k === 'amount' && i !== last && !next[last].paid) {
      const rest = Math.max(0, Math.round(total) - next.slice(0, last).reduce((a, s) => a + (+s.amount || 0), 0));
      next = next.map((r, j) => j === last ? { ...r, amount:rest } : r);
    }
    return next;
  });
  const rmSch = (i) => setSchedule(s => s.filter((_, j) => j !== i).map((r, j) => ({ ...r, no:j + 1 })));
  // Thêm đợt mới: tự điền phần còn lại (tổng − các đợt đã có); hạn = tháng kế của đợt trước.
  const addSch = () => setSchedule(list => {
    const rest = Math.max(0, Math.round(total) - list.reduce((a, s) => a + (+s.amount || 0), 0));
    const lastDue = list.length ? list[list.length - 1].dueDate : f.signDate;
    return [...list, { no:list.length + 1, amount:rest, dueDate:addMonths(lastDue, 1), condition:(lang === 'vi' ? 'Đợt ' : 'Installment ') + (list.length + 1) }];
  });

  const create = () => {
    if (!f.customer) { toast(f.direction === 'buy' ? (lang === 'vi' ? 'Chọn nhà cung cấp' : 'Select a vendor') : (lang === 'vi' ? 'Chọn khách hàng' : 'Select a customer'), 'error'); return; }
    if (!items.some(it => it.name.trim())) { toast(lang === 'vi' ? 'Thêm ít nhất 1 sản phẩm/dịch vụ' : 'Add at least one item', 'error'); return; }
    const rec = {
      code, contractNo:contractNoVal, direction:f.direction, category:f.category, signDate:f.signDate, customer:f.customer, rep:f.rep || null,
      termType:f.termType, startDate:f.termType === 'term' ? f.startDate : f.signDate,
      endDate:f.termType === 'term' ? f.endDate : null, remindBefore:+f.remindBefore || 30, status:f.status || 'active',
      billingCycle:f.termType === 'term' ? cycle : 'once',
      items:items.filter(it => it.name.trim()).map(it => ({ name:it.name, unit:it.unit, qty:+it.qty || 0, price:+it.price || 0, vat:+it.vat || 0, detail:(it.detail || '').trim(), showDetail:!!it.showDetail, ...(it.acceptDetail ? { acceptDetail:it.acceptDetail } : {}) })),
      schedule:schedule.map(s => ({ no:s.no, amount:+s.amount || 0, dueDate:s.dueDate, condition:s.condition, paid:!!s.paid, paidDate:s.paidDate || null })),
    };
    // Điều khoản soạn riêng HĐ: GIỮ nguyên khi sửa (form không đụng tới); HĐ mới chưa có (dùng mẫu chung).
    rec.docOverrides = { ...(editing ? (editing.docOverrides || {}) : {}) };
    // Uỷ quyền đại diện ĐỐI TÁC (chỉ HĐ bán có chọn rep từ Liên hệ): nhúng vào docOverrides để render + đóng băng theo phiên bản.
    if (f.rep && repAuth.auth) rec.docOverrides.partyAuth = { no:(repAuth.no || '').trim(), date:repAuth.date || '' };
    else delete rec.docOverrides.partyAuth;
    // Phiên bản: tạo mới → tự chốt V1 (bản đầu, đóng băng điều khoản hiệu lực); sửa → GIỮ lịch sử (chốt bản điều chỉnh thủ công ở chi tiết HĐ).
    if (editing) { rec.revisions = editing.revisions || []; }
    else {
      const initRev = makeRevision(rec, lang === 'vi' ? 'Bản đầu — tạo hợp đồng' : 'Initial version', p.me && p.me.name, p.appSettings);
      // HĐ cũ: ghi mốc bản đầu theo ngày ký (không phải ngày nhập liệu) để lịch sử phiên bản đúng năm.
      if (isOld && f.signDate) { const t0 = new Date(f.signDate + 'T00:00:00'); if (!isNaN(t0.getTime())) initRev.at = t0.toISOString(); }
      rec.revisions = [initRev];
    }
    if (editing) { p.patchContract(editing.code, rec); toast(lang === 'vi' ? 'Đã lưu hợp đồng' : 'Saved', 'success'); onClose(); return; }
    p.saveContract(rec);
    toast((lang === 'vi' ? 'Đã tạo hợp đồng ' : 'Created ') + code, 'success');
    onClose();
    p.navigate({ name:'module', module:'contracts', sub:'detail', id:code });
  };

  const cellInput = { height:26, padding:'0 6px', border:'1px solid var(--border-strong)', borderRadius:'var(--r-sm)', width:'100%', fontSize:'var(--fs-base)', background:'var(--bg)' };
  // Ô đầu (tên SP) cao hơn khi bật chi tiết (input + checkbox + textarea) → canh ĐỈNH cả hàng cho thẳng (như form báo giá).
  const cellTop = { verticalAlign:'top', paddingTop:5, paddingBottom:5 };

  return (
    <>
    <Modal staticBackdrop title={editing ? (lang === 'vi' ? 'Sửa hợp đồng' : 'Edit contract') : t('hd.new')} width={860} onClose={onClose}
      footer={<><div className="grow flex g8 items-center"><span className="subtle">{t('hd.total')}:</span><span className="mono" style={{ fontWeight:700, color:'var(--primary)', fontSize:'var(--fs-lg)' }}>{vnd(total)}</span></div>
        <button className="btn" onClick={onClose}>{t('c.cancel')}</button><button className="btn btn-primary" onClick={create}>{editing ? t('c.save') : t('c.create')}</button></>}>
      <div className="col g16">
        {/* section 1: contract info */}
        <div className="flex g12 items-center" style={{ padding:'2px 0' }}><span className="subtle">{t('hd.code')}:</span><span className="mono" style={{ fontWeight:600, color:'var(--primary)' }}>{code}</span>{!editing && <span className="badge badge-neutral">{lang === 'vi' ? 'tự sinh' : 'auto'}</span>}</div>
        <div className="flex g12 wrap">
          <div style={{ flex:'0 0 auto' }}><Field label={t('hd.direction')}><Segmented value={f.direction} onChange={v => setF(s => ({ ...s, direction:v, customer:'', rep:'' }))} options={[{ value:'sell', label:CONTRACT_DIRECTIONS.sell[lang] }, { value:'buy', label:CONTRACT_DIRECTIONS.buy[lang] }]} /></Field></div>
          <div style={{ flex:'1 1 200px' }}><Field label={t('hd.category')}><select className="select" value={f.category} onChange={e => set('category', e.target.value)}>{(p.catalogs.contractCats || []).map(c => <option key={c.id} value={c.id}>{c[lang]}</option>)}</select></Field></div>
          <div style={{ flex:'1 1 140px' }}><Field label={t('hd.signDate')}><DateInput value={f.signDate} onChange={v => set('signDate', v)} /></Field></div>
          {isOld && <div style={{ flex:'1 1 160px' }}><Field label={lang === 'vi' ? 'Trạng thái (HĐ cũ)' : 'Status (old)'} hint={lang === 'vi' ? 'Đánh dấu HĐ đã đóng/hủy.' : 'Mark a closed/cancelled contract.'}>
            <select className="select" value={f.status} onChange={e => set('status', e.target.value)}>
              {['active', 'completed', 'cancelled'].map(s => <option key={s} value={s}>{CONTRACT_STATUS[s][lang]}</option>)}
            </select>
          </Field></div>}
        </div>
        <div className="flex g12 wrap">
          {f.direction === 'buy'
            ? <div style={{ flex:'1 1 260px' }}><Field label={lang === 'vi' ? 'Số hợp đồng (do NCC cấp)' : 'Contract no. (from vendor)'}><input className="input" value={f.contractNo} onChange={e => set('contractNo', e.target.value)} placeholder={lang === 'vi' ? 'Nhập số HĐ của nhà cung cấp' : 'Vendor contract no.'} /></Field></div>
            : <div style={{ flex:'1 1 260px' }}><Field label={lang === 'vi' ? 'Số hợp đồng (tự cấp — sửa được)' : 'Contract no. (auto — editable)'} hint={lang === 'vi' ? 'Mặc định theo định dạng ở Cài đặt; sửa khi nhập hợp đồng cũ.' : 'Defaults to the Settings format; edit for old contracts.'}>
                <div className="flex g8 items-center">
                  <input className="input mono" value={contractNoVal} onChange={e => set('contractNo', e.target.value)} placeholder={autoContractNo} />
                  {(f.contractNo || '').trim() && f.contractNo !== autoContractNo && <button type="button" className="btn btn-sm btn-ghost" title={lang === 'vi' ? 'Tự cấp lại' : 'Reset to auto'} onClick={() => set('contractNo', '')}><i className="bi bi-arrow-counterclockwise"></i></button>}
                </div>
              </Field></div>}
        </div>

        {/* section 2: parties — chọn KH + người đại diện, cho phép thêm mới inline */}
        <div className="hr"></div>
        <div style={{ fontWeight:600, fontSize:'var(--fs-md)' }}>{f.direction === 'buy' ? t('hd.vendor') : t('hd.parties')}</div>
        {f.direction === 'buy' ? (
          <Field label={t('hd.vendor')}>
            <select className="select" value={f.customer} onChange={e => set('customer', e.target.value)}>
              <option value="">— {lang === 'vi' ? 'chọn nhà cung cấp' : 'select vendor'} —</option>
              {(p.vendors || []).map(v => <option key={v.code} value={v.code}>{v.code} · {v.name}</option>)}
            </select>
          </Field>
        ) : (
          <PartyFields customer={f.customer} rep={f.rep} onCustomer={v => set('customer', v)} onRep={v => set('rep', v)} />
        )}
        {/* Uỷ quyền của người đại diện đối tác — chỉ hiện khi HĐ bán đã chọn người đại diện từ Liên hệ. */}
        {f.direction !== 'buy' && f.rep && (
          <div className="flex g12 wrap items-start">
            <div style={{ flex:'0 0 240px' }}><Field label={lang === 'vi' ? 'Uỷ quyền (đối tác)' : 'Authorization (partner)'}>
              <label className="flex g8 items-center" style={{ height:'var(--control-h)', cursor:'pointer' }}>
                <input type="checkbox" checked={repAuth.auth} onChange={e => setRepAuth(s => ({ ...s, auth:e.target.checked }))} />{lang === 'vi' ? 'Đại diện theo uỷ quyền' : 'By authorization'}
              </label></Field></div>
            {repAuth.auth && <div style={{ flex:1, minWidth:160 }}><Field label={lang === 'vi' ? 'Số giấy uỷ quyền' : 'Authorization no.'}><input className="input" value={repAuth.no} onChange={e => setRepAuth(s => ({ ...s, no:e.target.value }))} placeholder={lang === 'vi' ? 'VD: 02/2026/UQ' : 'e.g. 02/2026/UQ'} /></Field></div>}
            {repAuth.auth && <div style={{ flex:'0 0 160px' }}><Field label={lang === 'vi' ? 'Ngày uỷ quyền' : 'Authorization date'}><DateInput value={repAuth.date} onChange={v => setRepAuth(s => ({ ...s, date:v }))} /></Field></div>}
          </div>
        )}

        {/* section 3: term */}
        <div className="hr"></div>
        <div className="col g12">
          <div className="flex g12 items-center">
            <div style={{ fontWeight:600, fontSize:'var(--fs-md)' }}>{t('hd.term')}</div>
            <Segmented value={f.termType} onChange={v => set('termType', v)} options={[{ value:'once', label:TERM_TYPES.once[lang] }, { value:'term', label:TERM_TYPES.term[lang] }]} />
          </div>
          {f.termType === 'term' && (
            <div className="flex g12 wrap">
              <div style={{ flex:'1 1 150px' }}><Field label={t('hd.start')}><DateInput value={f.startDate} onChange={v => set('startDate', v)} /></Field></div>
              <div style={{ flex:'1 1 150px' }}><Field label={t('hd.end')}><DateInput value={f.endDate} onChange={v => set('endDate', v)} /></Field></div>
              <div style={{ flex:'1 1 150px' }}><Field label={lang === 'vi' ? 'Nhắc trước (ngày)' : 'Remind (days)'}><input type="number" className="input" value={f.remindBefore} onChange={e => set('remindBefore', e.target.value)} /></Field></div>
            </div>
          )}
        </div>

        {/* section 4: items */}
        <div className="hr"></div>
        <div className="flex justify-between items-center"><div style={{ fontWeight:600, fontSize:'var(--fs-md)' }}>{t('hd.items')}</div>
          <div className="flex g8 items-center">
            <button className="btn btn-sm btn-ghost" onClick={() => setAddProdOpen(true)}><i className="bi bi-box-seam"></i>{lang === 'vi' ? 'Tạo SP mới' : 'New product'}</button>
            <button className="btn btn-sm btn-subtle" onClick={addItem}><i className="bi bi-plus-lg"></i>{t('hd.addItem')}</button>
          </div>
        </div>
        <div className="subtle" style={{ fontSize:'var(--fs-sm)', marginTop:-4 }}><i className="bi bi-magic" style={{ marginRight:4 }}></i>{lang === 'vi' ? 'Chọn từ Danh mục Dịch vụ để tự điền ĐVT, giá & VAT. Sản phẩm chưa có? Bấm "Tạo SP mới".' : 'Pick from the catalog to autofill unit, price & VAT. Need a new one? Click "New product".'}</div>
        <datalist id="cn-products">{products.map(pr => <option key={pr.code} value={pr.name}>{vnd(priceOf(pr))} · {pr.code}</option>)}</datalist>
        <div style={{ overflow:'auto' }}>
          <table className="tbl" style={{ minWidth:640 }}>
            <thead><tr><th>{t('hd.items')}</th><th style={{ width:64 }}>{t('hd.unit')}</th><th style={{ width:84 }} className="num">{t('hd.qty')}</th><th style={{ width:120 }} className="num">{t('hd.price')}</th><th style={{ width:64 }} className="num">{t('hd.vat')}%</th><th style={{ width:110 }} className="num">{t('hd.total')}</th><th style={{ width:30 }}></th></tr></thead>
            <tbody>
              {items.map((it, i) => { const line = (+it.qty || 0) * (+it.price || 0); const tt = line * (1 + (+it.vat || 0) / 100); return (
                <tr key={i} style={{ cursor:'default' }}>
                  <td style={cellTop}>
                    {/* onFocus select-all: đã chọn SP rồi vẫn đổi được — gõ là thay toàn bộ, danh sách gợi ý mở lại */}
                    <input style={cellInput} list="cn-products" value={it.name} placeholder={lang === 'vi' ? 'Tên sản phẩm / dịch vụ' : 'Item name'} onChange={e => onItemName(i, e.target.value)} onFocus={e => e.target.select()} />
                    <label className="flex g4 items-center" style={{ fontSize:'var(--fs-sm)', color:'var(--text-muted)', marginTop:4, cursor:'pointer' }}>
                      <input type="checkbox" checked={!!it.showDetail} onChange={() => toggleDetail(i)} />{lang === 'vi' ? 'Hiển thị chi tiết' : 'Show detail'}
                    </label>
                    {it.showDetail && <textarea rows={2} style={{ ...cellInput, height:'auto', marginTop:4, fontSize:'var(--fs-sm)', resize:'vertical', padding:'4px 6px' }} value={it.detail || ''} placeholder={lang === 'vi' ? 'Chi tiết (sửa được)' : 'Detail (editable)'} onChange={e => upItem(i, 'detail', e.target.value)} />}
                  </td>
                  <td style={cellTop}><input style={cellInput} value={it.unit} onChange={e => upItem(i, 'unit', e.target.value)} /></td>
                  <td style={cellTop}><input className="no-spin" style={{ ...cellInput, textAlign:'right' }} type="number" value={it.qty} onChange={e => upItem(i, 'qty', e.target.value)} /></td>
                  <td style={cellTop}><MoneyInput className="" style={{ ...cellInput, textAlign:'right' }} value={it.price} onChange={v => upItem(i, 'price', v)} /></td>
                  <td style={cellTop}><input className="no-spin" style={{ ...cellInput, textAlign:'right' }} type="number" value={it.vat} onChange={e => upItem(i, 'vat', e.target.value)} /></td>
                  <td className="num mono" style={{ ...cellTop, fontWeight:600, lineHeight:'26px' }}>{vnd(tt)}</td>
                  <td style={{ ...cellTop, textAlign:'center' }}><button className="iconbtn" style={{ width:22, height:22, marginTop:2 }} onClick={() => rmItem(i)}><i className="bi bi-trash" style={{ fontSize:12 }}></i></button></td>
                </tr>
              ); })}
            </tbody>
            <tfoot>
              <tr style={{ cursor:'default' }}><td colSpan="4"></td><td className="num muted">{t('hd.subtotal')}</td><td className="num mono">{vnd(tot.sub)}</td><td></td></tr>
              <tr style={{ cursor:'default' }}><td colSpan="4"></td><td className="num muted">{t('hd.vatTotal')}</td><td className="num mono">{vnd(tot.vat)}</td><td></td></tr>
              <tr style={{ cursor:'default', background:'var(--bg-subtle)' }}><td colSpan="4"></td><td className="num" style={{ fontWeight:700 }}>{t('hd.total')}</td><td className="num mono" style={{ fontWeight:700, color:'var(--primary)' }}>{vnd(total)}</td><td></td></tr>
            </tfoot>
          </table>
        </div>

        {/* section 5: schedule */}
        <div className="hr"></div>
        <div className="flex justify-between items-center wrap g8"><div style={{ fontWeight:600, fontSize:'var(--fs-md)' }}>{t('hd.schedule')}</div>
          <div className="flex g8 items-center wrap">
            {/* HĐ KỲ HẠN: chọn chu kỳ thu (thuê dịch vụ) → sinh lịch từ ngày bắt đầu → kết thúc */}
            {f.termType === 'term' && (<>
              <span className="subtle" style={{ fontSize:'var(--fs-base)' }}>{lang === 'vi' ? 'Chu kỳ' : 'Cycle'}</span>
              <select className="select" style={{ width:'auto' }} value={cycle} onChange={e => setCycle(e.target.value)}>
                {Object.entries(CONTRACT_BILLING_CYCLES).map(([k, v]) => <option key={k} value={k}>{v[lang] || v.vi}</option>)}
              </select>
              {cycle !== 'once' && <button className="btn btn-sm btn-accent" onClick={genByCycle} title={lang === 'vi' ? 'Sinh các đợt đầu-mỗi-kỳ từ ngày bắt đầu đến kết thúc, chia đều từ tổng' : 'Generate installments per cycle from start to end'}><i className="bi bi-arrow-repeat"></i>{lang === 'vi' ? 'Tạo lịch theo chu kỳ' : 'Generate by cycle'}</button>}
            </>)}
            {(f.termType !== 'term' || cycle === 'once') && (<>
              <span className="subtle" style={{ fontSize:'var(--fs-base)' }}>{lang === 'vi' ? 'Số lần' : 'Installments'}</span>
              <input type="number" className="input" style={{ width:64 }} value={nInst} onChange={e => setNInst(e.target.value)} min="1" max="12" />
              <button className="btn btn-sm" onClick={genSchedule}><i className="bi bi-magic"></i>{t('hd.genSchedule')}</button>
            </>)}
            <button className="btn btn-sm btn-subtle" onClick={addSch} title={lang === 'vi' ? 'Đợt mới tự điền phần còn lại (tổng − các đợt trước)' : 'New installment auto-fills the remainder'}><i className="bi bi-plus-lg"></i>{lang === 'vi' ? 'Thêm đợt' : 'Add installment'}</button></div>
        </div>
        <div style={{ overflow:'auto' }}>
          <table className="tbl" style={{ minWidth:760 }}>
            <thead><tr><th style={{ width:44 }}>{t('hd.installment')}</th><th style={{ width:140 }} className="num">{lang === 'vi' ? 'Số tiền' : 'Amount'}</th><th style={{ width:150 }}>{t('hd.dueDate')}</th><th>{t('hd.condition')}</th><th style={{ width:56, textAlign:'center' }}>{f.direction === 'buy' ? (lang === 'vi' ? 'Đã trả' : 'Paid') : (lang === 'vi' ? 'Đã thu' : 'Paid')}</th><th style={{ width:140 }}>{f.direction === 'buy' ? (lang === 'vi' ? 'Ngày trả' : 'Paid date') : (lang === 'vi' ? 'Ngày thu' : 'Paid date')}</th><th style={{ width:30 }}></th></tr></thead>
            <tbody>
              {schedule.map((s, i) => (
                <tr key={i} style={{ cursor:'default' }}>
                  <td style={{ fontWeight:600 }}>{s.no}</td>
                  <td><MoneyInput className="" style={{ ...cellInput, textAlign:'right' }} value={s.amount} onChange={v => upSch(i, 'amount', v)} /></td>
                  <td><DateInput className="" style={cellInput} value={s.dueDate} onChange={v => upSch(i, 'dueDate', v)} /></td>
                  <td><input style={cellInput} value={s.condition} onChange={e => upSch(i, 'condition', e.target.value)} /></td>
                  <td style={{ textAlign:'center' }}><input type="checkbox" checked={!!s.paid} onChange={e => { const v = e.target.checked; setSchedule(list => list.map((r, j) => j === i ? { ...r, paid:v, paidDate:v ? (r.paidDate || r.dueDate) : r.paidDate } : r)); }} /></td>
                  <td><DateInput className="" style={{ ...cellInput, opacity:s.paid ? 1 : 0.5 }} disabled={!s.paid} value={s.paidDate || ''} onChange={v => upSch(i, 'paidDate', v)} /></td>
                  <td style={{ textAlign:'center' }}><button className="iconbtn" style={{ width:22, height:22 }} onClick={() => rmSch(i)}><i className="bi bi-trash" style={{ fontSize:12 }}></i></button></td>
                </tr>
              ))}
            </tbody>
            <tfoot><tr style={{ cursor:'default', background:'var(--bg-subtle)' }}><td>Σ</td><td className="num mono" style={{ fontWeight:700, color:schedule.reduce((a, s) => a + (+s.amount || 0), 0) === Math.round(total) ? 'var(--success)' : 'var(--warning)' }}>{vnd(schedule.reduce((a, s) => a + (+s.amount || 0), 0))}</td><td colSpan="5" className="muted">{schedule.reduce((a, s) => a + (+s.amount || 0), 0) === Math.round(total) ? (lang === 'vi' ? 'Khớp tổng giá trị' : 'Matches total') : (lang === 'vi' ? 'Chưa khớp tổng' : 'Does not match total')}</td></tr></tfoot>
          </table>
        </div>
      </div>
    </Modal>
    {addProdOpen && <NewProductModal onClose={() => setAddProdOpen(false)} onCreated={addItemFromProduct} />}
    </>
  );
}

Object.assign(window, { NewContractModal });
