// reports.jsx — khung báo cáo dùng chung cho mọi module (Hợp đồng · Sản phẩm · Báo giá · Hỗ trợ…):
//   • preset kỳ (Tháng này / Quý trước / Q1–4 / Năm nay…) + chọn khoảng ngày tuỳ ý
//   • biểu đồ nhẹ (cột theo tháng, đường xu hướng, donut, thanh xếp hạng)
//   • xuất: .xlsx thật (SheetJS) + in-ra-PDF (mở trang A4 sạch)
// Không backend — mọi số liệu tính từ state (p.*). Chỉ đọc, không ghi.

/* ============ kỳ báo cáo ============ */
function rpPad(n){ return String(n).padStart(2, '0'); }
function rpMk(y, m, d){ return y + '-' + rpPad(m) + '-' + rpPad(d); }
function rpLastDay(y, m){ return new Date(y, m, 0).getDate(); }         // m tính từ 1
function rpMonthRange(y, m){ return { from:rpMk(y, m, 1), to:rpMk(y, m, rpLastDay(y, m)) }; }
function rpQuarterRange(y, q){ return { from:rpMk(y, (q - 1) * 3 + 1, 1), to:rpMk(y, q * 3, rpLastDay(y, q * 3)) }; }

function reportPresets(lang) {
  const parts = (typeof TODAY !== 'undefined' ? TODAY : '2026-06-07').split('-').map(Number);
  const Y = parts[0], M = parts[1];
  const curQ = Math.floor((M - 1) / 3) + 1;
  const lqY = curQ === 1 ? Y - 1 : Y;
  const lq = curQ === 1 ? 4 : curQ - 1;
  const L = (vi, en) => lang === 'vi' ? vi : en;
  const lastM = M === 1 ? rpMonthRange(Y - 1, 12) : rpMonthRange(Y, M - 1);
  return [
    Object.assign({ id:'thismonth', label:L('Tháng này', 'This month') }, rpMonthRange(Y, M)),
    Object.assign({ id:'lastmonth', label:L('Tháng trước', 'Last month') }, lastM),
    Object.assign({ id:'lastquarter', label:L('Quý trước', 'Last quarter') }, rpQuarterRange(lqY, lq)),
    Object.assign({ id:'q1', label:'Q1 ' + Y }, rpQuarterRange(Y, 1)),
    Object.assign({ id:'q2', label:'Q2 ' + Y }, rpQuarterRange(Y, 2)),
    Object.assign({ id:'q3', label:'Q3 ' + Y }, rpQuarterRange(Y, 3)),
    Object.assign({ id:'q4', label:'Q4 ' + Y }, rpQuarterRange(Y, 4)),
    { id:'thisyear', label:L('Năm nay', 'This year'), from:rpMk(Y, 1, 1), to:rpMk(Y, 12, 31) },
    { id:'lastyear', label:L('Năm trước', 'Last year'), from:rpMk(Y - 1, 1, 1), to:rpMk(Y - 1, 12, 31) },
  ];
}

function useReportPeriod(defaultId) {
  const { lang } = useLang();
  const presets = reportPresets(lang);
  const def = presets.find(p => p.id === (defaultId || 'thismonth')) || presets[0];
  const [st, setSt] = React.useState({ from:def.from, to:def.to, presetId:def.id });
  return {
    from:st.from, to:st.to, presetId:st.presetId, presets,
    setPreset:(id) => { const p = presets.find(x => x.id === id); if (p) setSt({ from:p.from, to:p.to, presetId:id }); },
    setFrom:(v) => setSt(s => ({ ...s, from:v, presetId:null })),
    setTo:(v) => setSt(s => ({ ...s, to:v, presetId:null })),
  };
}

function inPeriod(dateStr, period) {
  if (!dateStr) return false;
  const d = String(dateStr).slice(0, 10);
  return d >= period.from && d <= period.to;
}
function rpMonthKey(dateStr){ return String(dateStr).slice(0, 7); }
function monthsInPeriod(period) {
  const f = period.from.split('-').map(Number), t = period.to.split('-').map(Number);
  let y = f[0], m = f[1]; const out = [];
  while ((y < t[0] || (y === t[0] && m <= t[1])) && out.length < 60) {
    out.push({ key:y + '-' + rpPad(m), label:rpPad(m) + '/' + String(y).slice(2) });
    m++; if (m > 12) { m = 1; y++; }
  }
  return out;
}
function tallyByMonth(items, dateOf, valOf) {
  const map = {};
  items.forEach(it => { const k = rpMonthKey(dateOf(it)); if (!k || k.length < 7) return; map[k] = (map[k] || 0) + (valOf ? valOf(it) : 1); });
  return map;
}
function fmtVNDate(s){ if (!s) return ''; const p = String(s).slice(0, 10).split('-'); return p[2] + '/' + p[1] + '/' + p[0]; }

const REPORT_COLORS = ['var(--primary)', 'var(--accent)', '#7A5AF8', '#F59E0B', '#1F9D57', '#D14343', '#0FB0AB', '#C77700', '#0B4FBF', '#98A2B3'];

/* ============ biểu đồ ============ */
function ReportBars({ months, series, color, money, height }) {
  color = color || 'var(--primary)'; height = height || 150;
  const vals = months.map(m => series[m.key] || 0);
  const max = Math.max.apply(null, vals.concat([1]));
  return (
    <div className="rb-wrap">
      <div className="rb-bars" style={{ height }}>
        {months.map((m, i) => { const v = vals[i]; const h = v > 0 ? Math.max(2, Math.round(v / max * 100)) : 0;
          return (
            <div key={m.key} className="rb-col" title={m.label + ': ' + (money ? vndShort(v) : v)}>
              <span className="rb-val">{v ? (money ? vndShort(v) : v) : ''}</span>
              <span className="rb-bar" style={{ height:h + '%', background:color }}></span>
            </div>
          );
        })}
      </div>
      <div className="rb-xrow">{months.map(m => <span key={m.key} className="rb-x">{m.label}</span>)}</div>
    </div>
  );
}

function ReportTrend({ months, series, color, money, height }) {
  color = color || 'var(--accent)'; height = height || 150;
  const vals = months.map(m => series[m.key] || 0);
  const max = Math.max.apply(null, vals.concat([1]));
  const n = months.length;
  const pts = vals.map((v, i) => [n <= 1 ? 50 : (i / (n - 1)) * 100, 100 - (v / max * 92) - 4]);
  const line = pts.map((p, i) => (i ? 'L' : 'M') + p[0].toFixed(2) + ' ' + p[1].toFixed(2)).join(' ');
  const area = 'M0 100 ' + pts.map(p => 'L' + p[0].toFixed(2) + ' ' + p[1].toFixed(2)).join(' ') + ' L100 100 Z';
  return (
    <div className="rb-wrap">
      <svg viewBox="0 0 100 100" preserveAspectRatio="none" style={{ width:'100%', height }} className="rt-svg" data-om-raster>
        <path d={area} fill={color} opacity="0.12"></path>
        <path d={line} fill="none" stroke={color} strokeWidth="1.6" vectorEffect="non-scaling-stroke" strokeLinejoin="round"></path>
      </svg>
      <div className="rb-xrow">{months.map(m => <span key={m.key} className="rb-x">{m.label}</span>)}</div>
    </div>
  );
}

function ReportDonut({ slices, money, size }) {
  size = size || 148;
  const sum = slices.reduce((s, x) => s + x.value, 0);
  const R = 15.9, C = 2 * Math.PI * R; let off = 0;
  return (
    <div className="rd-wrap">
      <svg viewBox="0 0 42 42" style={{ width:size, height:size, flex:'none' }} className="rd-svg" data-om-raster>
        <circle cx="21" cy="21" r={R} fill="none" stroke="var(--bg-sunken)" strokeWidth="5.5"></circle>
        {sum > 0 && slices.map((s, i) => { const len = s.value / sum * C; const el = (
          <circle key={i} cx="21" cy="21" r={R} fill="none" stroke={s.color} strokeWidth="5.5"
            strokeDasharray={len.toFixed(3) + ' ' + (C - len).toFixed(3)} strokeDashoffset={(-off).toFixed(3)} transform="rotate(-90 21 21)"></circle>);
          off += len; return el; })}
        <text x="21" y="20.4" textAnchor="middle" className="rd-total">{money ? vndShort(sum) : sum}</text>
      </svg>
      <div className="rd-legend">
        {slices.map((s, i) => (
          <div key={i} className="rd-li">
            <span className="rd-dot" style={{ background:s.color }}></span>
            <span className="grow truncate">{s.label}</span>
            <span className="mono rd-lv">{money ? vndShort(s.value) : s.value}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

function ReportRank({ rows, money, max }) {
  const m = max || Math.max.apply(null, rows.map(r => r.value).concat([1]));
  if (!rows.length) return <EmptyState icon="bi-bar-chart" text="—" />;
  return (
    <div className="rank-list">
      {rows.map((r, i) => (
        <div key={i} className="rank-row">
          <span className="rank-lb truncate" title={r.label}>{r.label}</span>
          <span className="rank-track"><span className="rank-fill" style={{ width:Math.max(2, r.value / m * 100) + '%', background:r.color || 'var(--primary)' }}></span></span>
          <span className="rank-v mono">{money ? vndShort(r.value) : r.value}</span>
        </div>
      ))}
    </div>
  );
}

/* ============ xuất Excel ============ */
function exportReportXLSX(sheets, filename, toast, lang) {
  if (typeof XLSX === 'undefined') { toast && toast(lang === 'vi' ? 'Thư viện Excel chưa sẵn sàng, thử lại sau giây lát' : 'Excel library not ready yet', 'error'); return; }
  const wb = XLSX.utils.book_new();
  sheets.forEach((sh, i) => {
    const ws = XLSX.utils.aoa_to_sheet([sh.header].concat(sh.rows));
    if (sh.widths) ws['!cols'] = sh.widths.map(w => ({ wch:w }));
    XLSX.utils.book_append_sheet(wb, ws, (sh.name || ('Sheet' + (i + 1))).slice(0, 31));
  });
  XLSX.writeFile(wb, filename + '.xlsx');
  toast && toast(lang === 'vi' ? 'Đã xuất Excel' : 'Excel exported', 'success');
}

function rpEsc(s){ return String(s == null ? '' : s).replace(/[&<>"]/g, c => ({ '&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;' }[c])); }

/* ============ khung (tiêu đề + hành động + thanh điều khiển + vùng in) ============ */
function ReportShell({ title, subtitle, period, onExcel, filename, children }) {
  const p = usePortal();
  const { lang } = useLang();
  const toast = useToast();
  const docRef = React.useRef(null);
  const brandName = (p.branding && p.branding.name) || 'S.W.O';
  const periodText = (lang === 'vi' ? 'Kỳ báo cáo: ' : 'Period: ') + fmtVNDate(period.from) + ' – ' + fmtVNDate(period.to);

  const doPrint = () => {
    const node = docRef.current; if (!node) return;
    const abs = f => { try { return new URL(f, location.href).href; } catch (e) { return f; } };
    const head = '<div class="rp-head"><div class="rp-brand">' + rpEsc(brandName) + '</div>'
      + '<div class="rp-meta"><div class="rp-title">' + rpEsc(title) + '</div>'
      + (subtitle ? '<div class="rp-sub">' + rpEsc(subtitle) + '</div>' : '')
      + '<div class="rp-period">' + rpEsc(periodText) + '</div></div></div>';
    const html = '<!DOCTYPE html><html lang="' + lang + '"><head><meta charset="utf-8"><title>' + rpEsc(title) + '</title>'
      + '<link rel="stylesheet" href="' + abs('portal/vendor/bootstrap-icons.css') + '">'
      + '<link rel="stylesheet" href="' + abs('portal/styles.css') + '">'
      + '<link rel="stylesheet" href="' + abs('portal/layout.css') + '">'
      + '<style>@page{size:A4;margin:13mm} html,body{background:#fff;margin:0;padding:0;color-scheme:light}'
      + '.report-doc{padding:0;max-width:none}.report-controls,.report-actions{display:none!important}'
      + '.rp-head{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;border-bottom:2px solid var(--primary);padding-bottom:10px;margin-bottom:16px}'
      + '.rp-brand{font-weight:800;font-size:19px;color:var(--primary);letter-spacing:-.02em}'
      + '.rp-meta{text-align:right}.rp-title{font-weight:700;font-size:15px}.rp-sub{color:#667085;font-size:11.5px;margin-top:1px}.rp-period{font-size:11.5px;margin-top:3px}'
      + '.dash-grid{gap:12px}.card{break-inside:avoid;box-shadow:none}.kpi-strip{margin-bottom:12px}'
      + '.rb-bars .rb-bar,.rank-fill,.rd-svg circle,.rt-svg path{-webkit-print-color-adjust:exact;print-color-adjust:exact}'
      + '</style></head><body><div class="report-doc">' + head + node.innerHTML + '</div>'
      + '<script>window.onload=function(){setTimeout(function(){window.print();},450)};<\/script></body></html>';
    if (typeof printDocument === 'function') {
      if (!printDocument(html)) toast(lang === 'vi' ? 'Trình duyệt chặn cửa sổ in — hãy cho phép pop-up' : 'Pop-up blocked — allow pop-ups', 'error');
    } else { window.print(); }
  };

  return (
    <div className="page pagefade">
      <div className="page-head">
        <div><h1>{title}</h1>{subtitle && <div className="sub">{subtitle}</div>}</div>
        <div className="flex g8 report-actions">
          <button className="btn" onClick={doPrint}><i className="bi bi-filetype-pdf"></i>{lang === 'vi' ? 'PDF / In' : 'PDF / Print'}</button>
          <button className="btn btn-primary" onClick={onExcel}><i className="bi bi-file-earmark-excel"></i>Excel</button>
        </div>
      </div>
      <ReportControls period={period} />
      <div className="report-doc" ref={docRef}>{children}</div>
    </div>
  );
}

function ReportControls({ period }) {
  const { lang } = useLang();
  return (
    <div className="report-controls">
      <div className="rc-presets">
        {period.presets.map(pr => (
          <button key={pr.id} className={'rc-chip' + (period.presetId === pr.id ? ' active' : '')} onClick={() => period.setPreset(pr.id)}>{pr.label}</button>
        ))}
      </div>
      <div className="rc-dates">
        <div className="rc-date"><DateInput value={period.from} onChange={v => period.setFrom(v)} /></div>
        <span className="rc-dash">–</span>
        <div className="rc-date"><DateInput value={period.to} onChange={v => period.setTo(v)} /></div>
      </div>
    </div>
  );
}

Object.assign(window, {
  reportPresets, useReportPeriod, inPeriod, monthsInPeriod, tallyByMonth, rpMonthKey, fmtVNDate, REPORT_COLORS,
  ReportBars, ReportTrend, ReportDonut, ReportRank, exportReportXLSX, ReportShell, ReportControls,
});
