/* ============ Shared UI components ============ */
const { useState, useEffect, useRef } = React;
const D = window.DATA;

/* --- Badge --- */
function Status({ status }) {
  const s = D.statusInfo[status] || { label: status, badge: 'muted' };
  return <span className={'badge ' + s.badge}><span className="dot"></span>{s.label}</span>;
}

/* --- Stat card --- */
function Stat({ label, icon, iconBg, iconColor, value, unit, delta, deltaDir, sub }) {
  return (
    <div className="card stat">
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
        <div className="lbl">{label}</div>
        {icon && (
          <div className="stat-ic" style={{ background: iconBg || 'var(--primary-tint)', color: iconColor || 'var(--primary)' }}>
            <Icon name={icon} size={18} />
          </div>
        )}
      </div>
      <div className="val">{value}{unit && <span className="unit">{unit}</span>}</div>
      {(delta || sub) && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          {delta && <div className={'delta ' + (deltaDir || 'up')}><Icon name={deltaDir === 'down' ? 'arrowDown' : 'arrowUp'} size={13} />{delta}</div>}
          {sub && <div style={{ fontSize: 12, color: 'var(--ink-3)' }}>{sub}</div>}
        </div>
      )}
    </div>
  );
}

/* --- Modal --- */
function Modal({ title, icon, children, onClose, footer, wide }) {
  useEffect(() => {
    const h = (e) => e.key === 'Escape' && onClose();
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
  }, []);
  return (
    <div className="overlay" onMouseDown={(e) => e.target === e.currentTarget && onClose()}>
      <div className="modal" style={wide ? { maxWidth: 820 } : null}>
        <div className="modal-head">
          {icon && <div className="stat-ic" style={{ background: 'var(--primary-tint)', color: 'var(--primary)', width: 32, height: 32 }}><Icon name={icon} size={17} /></div>}
          <h3>{title}</h3>
          <button className="x-btn" onClick={onClose}><Icon name="x" size={18} /></button>
        </div>
        <div className="modal-body">{children}</div>
        {footer && <div className="modal-foot">{footer}</div>}
      </div>
    </div>
  );
}

/* --- Toast --- */
function useToast() {
  const [toasts, setToasts] = useState([]);
  const push = (msg, kind = 'ok') => {
    const id = Math.random();
    setToasts((t) => [...t, { id, msg, kind }]);
    setTimeout(() => setToasts((t) => t.filter((x) => x.id !== id)), 3200);
  };
  const node = (
    <div style={{ position: 'fixed', bottom: 22, left: '50%', transform: 'translateX(-50%)', zIndex: 200, display: 'flex', flexDirection: 'column', gap: 8, alignItems: 'center' }}>
      {toasts.map((t) => (
        <div key={t.id} style={{
          display: 'flex', alignItems: 'center', gap: 9, padding: '11px 18px', borderRadius: 11,
          background: 'var(--ink)', color: '#fff', fontSize: 13.5, fontWeight: 600,
          boxShadow: 'var(--shadow-lg)', animation: 'pop .2s ease',
        }}>
          <Icon name={t.kind === 'ok' ? 'checkCircle' : t.kind === 'warn' ? 'alert' : 'info'} size={17}
            style={{ color: t.kind === 'ok' ? 'oklch(0.7 0.13 162)' : t.kind === 'warn' ? 'oklch(0.78 0.13 80)' : '#9cc' }} />
          {t.msg}
        </div>
      ))}
    </div>
  );
  return [push, node];
}

/* --- Bar chart (revenue vs expense) --- */
function TrendChart({ data, height }) {
  const h = height || 180;
  const max = Math.max(...data.flatMap((d) => [d.rev, d.exp])) * 1.12;
  return (
    <div style={{ display: 'flex', alignItems: 'flex-end', gap: 'min(3.5%, 22px)', height: h, padding: '0 4px' }}>
      {data.map((d, i) => (
        <div key={i} style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 7, height: '100%', justifyContent: 'flex-end' }}>
          <div style={{ display: 'flex', gap: 4, alignItems: 'flex-end', height: '100%', width: '100%', justifyContent: 'center' }}>
            <div title={'รายรับ ' + D.baht(d.rev)} style={{ width: '38%', maxWidth: 22, height: (d.rev / max * 100) + '%', background: 'var(--primary)', borderRadius: '5px 5px 0 0', transition: 'height .5s cubic-bezier(.2,.8,.3,1)' }}></div>
            <div title={'รายจ่าย ' + D.baht(d.exp)} style={{ width: '38%', maxWidth: 22, height: (d.exp / max * 100) + '%', background: 'var(--primary-tint2)', borderRadius: '5px 5px 0 0', transition: 'height .5s' }}></div>
          </div>
          <div style={{ fontSize: 11, color: 'var(--ink-3)', fontWeight: 600 }}>{D.thMonthsShort[d.m]}</div>
        </div>
      ))}
    </div>
  );
}

/* --- Donut chart for category breakdown --- */
function Donut({ segments, size, total, centerLabel, centerSub }) {
  const s = size || 170;
  const r = s / 2 - 16, cx = s / 2, cy = s / 2, circ = 2 * Math.PI * r;
  let offset = 0;
  const sum = segments.reduce((a, b) => a + b.value, 0) || 1;
  return (
    <div style={{ position: 'relative', width: s, height: s, flexShrink: 0 }}>
      <svg width={s} height={s} style={{ transform: 'rotate(-90deg)' }}>
        <circle cx={cx} cy={cy} r={r} fill="none" stroke="var(--line-2)" strokeWidth={18} />
        {segments.map((seg, i) => {
          const len = (seg.value / sum) * circ;
          const el = <circle key={i} cx={cx} cy={cy} r={r} fill="none" stroke={seg.color} strokeWidth={18}
            strokeDasharray={`${len} ${circ - len}`} strokeDashoffset={-offset} strokeLinecap="butt"
            style={{ transition: 'stroke-dasharray .6s' }} />;
          offset += len;
          return el;
        })}
      </svg>
      <div style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', textAlign: 'center' }}>
        <div>
          <div style={{ fontSize: 19, fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>{centerLabel}</div>
          {centerSub && <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>{centerSub}</div>}
        </div>
      </div>
    </div>
  );
}

/* --- Empty state --- */
function Empty({ icon, title, sub, action }) {
  return (
    <div style={{ textAlign: 'center', padding: '46px 20px', color: 'var(--ink-3)' }}>
      <div style={{ width: 54, height: 54, borderRadius: 14, background: 'var(--surface-2)', display: 'grid', placeItems: 'center', margin: '0 auto 14px', color: 'var(--ink-3)' }}>
        <Icon name={icon || 'docs'} size={26} />
      </div>
      <div style={{ fontWeight: 600, color: 'var(--ink-2)', fontSize: 15 }}>{title}</div>
      {sub && <div style={{ fontSize: 13, marginTop: 4 }}>{sub}</div>}
      {action && <div style={{ marginTop: 16 }}>{action}</div>}
    </div>
  );
}

/* --- File placeholder (receipt thumbnail) --- */
function ReceiptThumb({ small }) {
  const sz = small ? { width: 38, height: 48 } : { width: '100%', height: '100%' };
  return (
    <div style={{ ...sz, borderRadius: small ? 6 : 10, background: 'repeating-linear-gradient(135deg, var(--surface-2), var(--surface-2) 9px, oklch(0.94 0.005 165) 9px, oklch(0.94 0.005 165) 18px)', border: '1px solid var(--line)', display: 'grid', placeItems: 'center', color: 'var(--ink-3)', flexShrink: 0 }}>
      <Icon name="receipt" size={small ? 18 : 30} />
    </div>
  );
}

/* --- Month/Year period picker --- */
function periodShort(p) { return D.thMonthsShort[p.m] + ' ' + p.y; }
function periodLong(p) { return D.thMonths[p.m] + ' ' + p.y; }
const _bNow = new Date();
const CURRENT_PERIOD = { m: _bNow.getMonth(), y: _bNow.getFullYear() + 543 };
// true if an ISO date (YYYY-MM-DD, Gregorian) falls in the given พ.ศ. period
function inPeriod(iso, p) {
  if (!iso || !p) return false;
  const d = new Date(iso);
  if (isNaN(d)) return false;
  return d.getMonth() === p.m && (d.getFullYear() + 543) === p.y;
}

function MonthYearPicker({ period, onPick, onClose }) {
  const [year, setYear] = useState(period.y);
  return (
    <>
      <div style={{ position: 'fixed', inset: 0, zIndex: 49 }} onClick={onClose}></div>
      <div className="card" style={{ position: 'absolute', right: 0, top: 44, zIndex: 50, padding: 14, boxShadow: 'var(--shadow-lg)', width: 270 }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
          <button className="x-btn" onClick={() => setYear((y) => y - 1)}><Icon name="chevL" size={18} /></button>
          <div style={{ fontWeight: 700, fontSize: 15 }}>พ.ศ. {year}</div>
          <button className="x-btn" onClick={() => setYear((y) => y + 1)}><Icon name="chevR" size={18} /></button>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 6 }}>
          {D.thMonthsShort.map((m, i) => {
            const on = period.m === i && period.y === year;
            const isCur = i === CURRENT_PERIOD.m && year === CURRENT_PERIOD.y;
            return (
              <button key={i} onClick={() => onPick({ m: i, y: year })}
                style={{ padding: '11px 4px', borderRadius: 9, fontSize: 13, fontWeight: 600, position: 'relative',
                  border: '1px solid ' + (on ? 'var(--primary)' : 'transparent'),
                  background: on ? 'var(--primary)' : 'var(--surface-2)',
                  color: on ? '#fff' : 'var(--ink-2)' }}>
                {m}
                {isCur && !on && <span style={{ position: 'absolute', top: 5, right: 7, width: 5, height: 5, borderRadius: '50%', background: 'var(--primary)' }}></span>}
              </button>
            );
          })}
        </div>
        <button className="btn btn-ghost btn-sm btn-block" style={{ marginTop: 12 }} onClick={() => onPick({ ...CURRENT_PERIOD })}>
          <Icon name="calendar" className="ic" />เดือนปัจจุบัน ({periodShort(CURRENT_PERIOD)})
        </button>
      </div>
    </>
  );
}

/* --- Thai date picker (เดือนไทย + ปี พ.ศ.) — replaces native <input type=date> --- */
function ThaiDatePicker({ value, onChange, placeholder }) {
  const [open, setOpen] = useState(false);
  const [rect, setRect] = useState(null);
  const btnRef = useRef(null);
  const today = new Date();
  const sel = value ? new Date(value + 'T00:00:00') : null;
  const [view, setView] = useState(sel ? { y: sel.getFullYear(), m: sel.getMonth() } : { y: today.getFullYear(), m: today.getMonth() });

  useEffect(() => { if (open && sel) setView({ y: sel.getFullYear(), m: sel.getMonth() }); }, [open]);

  const toIso = (y, m, d) => y + '-' + String(m + 1).padStart(2, '0') + '-' + String(d).padStart(2, '0');
  const fmtDisplay = (d) => d.getDate() + ' ' + D.thMonths[d.getMonth()] + ' ' + (d.getFullYear() + 543);
  const toggle = () => { if (!open && btnRef.current) setRect(btnRef.current.getBoundingClientRect()); setOpen((o) => !o); };
  const prevM = () => setView((v) => { let m = v.m - 1, y = v.y; if (m < 0) { m = 11; y--; } return { y, m }; });
  const nextM = () => setView((v) => { let m = v.m + 1, y = v.y; if (m > 11) { m = 0; y++; } return { y, m }; });
  const pick = (d) => { onChange(toIso(view.y, view.m, d)); setOpen(false); };

  const firstDow = new Date(view.y, view.m, 1).getDay();
  const daysInMonth = new Date(view.y, view.m + 1, 0).getDate();
  const cells = [];
  for (let i = 0; i < firstDow; i++) cells.push(null);
  for (let d = 1; d <= daysInMonth; d++) cells.push(d);

  const popup = open && rect ? ReactDOM.createPortal(
    <>
      <div style={{ position: 'fixed', inset: 0, zIndex: 300 }} onMouseDown={() => setOpen(false)}></div>
      <div className="card" style={{ position: 'fixed', top: Math.min(rect.bottom + 6, window.innerHeight - 320), left: Math.max(8, Math.min(rect.left, window.innerWidth - 280)), zIndex: 301, padding: 12, width: 268, boxShadow: 'var(--shadow-lg)' }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
          <button type="button" className="x-btn" onClick={prevM}><Icon name="chevL" size={18} /></button>
          <div style={{ fontWeight: 700, fontSize: 14 }}>{D.thMonths[view.m]} {view.y + 543}</div>
          <button type="button" className="x-btn" onClick={nextM}><Icon name="chevR" size={18} /></button>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 2, marginBottom: 4 }}>
          {['อา', 'จ', 'อ', 'พ', 'พฤ', 'ศ', 'ส'].map((w, i) => <div key={i} style={{ textAlign: 'center', fontSize: 11, color: 'var(--ink-3)', fontWeight: 600, padding: '3px 0' }}>{w}</div>)}
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 2 }}>
          {cells.map((d, i) => {
            if (d === null) return <div key={i}></div>;
            const isSel = sel && sel.getFullYear() === view.y && sel.getMonth() === view.m && sel.getDate() === d;
            const isToday = today.getFullYear() === view.y && today.getMonth() === view.m && today.getDate() === d;
            return <button type="button" key={i} onClick={() => pick(d)}
              style={{ padding: '7px 0', borderRadius: 7, fontSize: 13, fontWeight: isSel ? 700 : 500, border: '1px solid ' + (isToday && !isSel ? 'var(--primary)' : 'transparent'), background: isSel ? 'var(--primary)' : 'transparent', color: isSel ? '#fff' : 'var(--ink)' }}
              onMouseEnter={(e) => { if (!isSel) e.currentTarget.style.background = 'var(--surface-2)'; }} onMouseLeave={(e) => { if (!isSel) e.currentTarget.style.background = 'transparent'; }}>{d}</button>;
          })}
        </div>
        <button type="button" className="btn btn-ghost btn-sm btn-block" style={{ marginTop: 10 }} onClick={() => { const t = new Date(); onChange(toIso(t.getFullYear(), t.getMonth(), t.getDate())); setOpen(false); }}>
          <Icon name="calendar" className="ic" />วันนี้
        </button>
      </div>
    </>, document.body) : null;

  return (
    <>
      <button ref={btnRef} type="button" className="input" style={{ textAlign: 'left', display: 'flex', alignItems: 'center', gap: 8, cursor: 'pointer' }} onClick={toggle}>
        <Icon name="calendar" size={16} style={{ color: 'var(--ink-3)', flexShrink: 0 }} />
        <span style={{ color: sel ? 'var(--ink)' : 'var(--ink-3)' }}>{sel ? fmtDisplay(sel) : (placeholder || 'เลือกวันที่')}</span>
      </button>
      {popup}
    </>
  );
}

Object.assign(window, { Status, Stat, Modal, useToast, TrendChart, Donut, Empty, ReceiptThumb, periodShort, periodLong, MonthYearPicker, CURRENT_PERIOD, ThaiDatePicker, inPeriod });
