// TTG Petty Cash — Shared UI components
const {
  fmtMoney, fmtDate, fmtDateTime, todayISO, addDays, sumItems, sumActual,
  DEPARTMENTS, USERS, ROLE_META, STATUS_META, statusBadge, Icon,
} = window;

// ---------- Generic Modal Menu ----------
function useOnClickOutside(ref, handler) {
  useEffect(() => {
    const fn = (e) => {
      if (!ref.current || ref.current.contains(e.target)) return;
      handler(e);
    };
    document.addEventListener('mousedown', fn);
    return () => document.removeEventListener('mousedown', fn);
  }, [ref, handler]);
}

// ---------- Sidebar ----------
function Sidebar({ active, onNavigate, user, counts, layout }) {
  if (layout === 'top') return null;
  const role = user.role;
  const items = [
    { id: 'dashboard',  label: 'หน้าหลัก',           en: 'Dashboard',      icon: 'home' },
    { id: 'new-request', label: 'สร้างคำขอเบิก',     en: 'New Request',    icon: 'plus' },
    { id: 'my-requests', label: 'คำขอของฉัน',        en: 'My Requests',    icon: 'fileText', badge: counts.mine },
    { id: 'clearing',    label: 'รอเคลียร์',          en: 'To Clear',       icon: 'wallet', badge: counts.toClear },
    null,
    (role !== 'staff') ? { id: 'approvals', label: 'รออนุมัติ', en: 'Approvals', icon: 'inbox', section: 'อนุมัติงาน', badge: counts.approvals } : null,
    (role === 'finance') ? { id: 'disburse', label: 'จ่ายเงิน',  en: 'Disburse',   icon: 'send', badge: counts.disburse } : null,
    (role === 'finance') ? { id: 'reconcile', label: 'ตรวจเคลียร์', en: 'Reconcile', icon: 'fileCheck', badge: counts.reconcile } : null,
    null,
    { id: 'all-requests', label: 'รายการทั้งหมด',     en: 'All Records',    icon: 'list', section: 'ทั่วไป' },
    { id: 'reports',      label: 'รายงาน',           en: 'Reports',         icon: 'chart' },
  ].filter(Boolean);

  return (
    <aside className="sidebar">
      <div className="sidebar__brand">
        <div className="brand-mark">TT</div>
        <div className="brand-text">
          <b>TTG Petty Cash</b>
          <span>เงินทดรองจ่าย</span>
        </div>
      </div>

      <div className="sidebar__section">เมนู</div>
      <div className="nav">
        {items.map((it, i) => {
          if (!it) return null;
          if (it.section) {
            return (
              <React.Fragment key={i}>
                <div className="sidebar__section" style={{paddingLeft: 14, marginTop: 8}}>{it.section}</div>
                <div className={`nav__item ${active === it.id ? 'active' : ''}`} onClick={() => onNavigate(it.id)}>
                  <Icon name={it.icon} size={17}/>
                  <span>{it.label}</span>
                  {it.badge ? <span className="nav__badge">{it.badge}</span> : null}
                </div>
              </React.Fragment>
            );
          }
          return (
            <div key={i} className={`nav__item ${active === it.id ? 'active' : ''}`} onClick={() => onNavigate(it.id)}>
              <Icon name={it.icon} size={17}/>
              <span>{it.label}</span>
              {it.badge ? <span className="nav__badge">{it.badge}</span> : null}
            </div>
          );
        })}
      </div>

      <div className="sidebar__footer">
        <div className="avatar">{user.initials}</div>
        <div className="user-mini">
          <b>{user.name}</b>
          <span>{ROLE_META[user.role].label}</span>
        </div>
        <button className="icon-btn" style={{color: '#A4A9C6'}} title="ออกจากระบบ">
          <Icon name="logout" size={16}/>
        </button>
      </div>
    </aside>
  );
}

// ---------- Topbar ----------
function Topbar({ title, crumb, search, setSearch, user, onSwitchRole, onNavigate, active }) {
  const [menuOpen, setMenuOpen] = useState(false);
  const [notifOpen, setNotifOpen] = useState(false);
  const menuRef = useRef(); const notifRef = useRef();
  useOnClickOutside(menuRef, () => setMenuOpen(false));
  useOnClickOutside(notifRef, () => setNotifOpen(false));

  return (
    <header className="topbar">
      <div>
        <div className="topbar__title">{title}</div>
        {crumb ? <div className="topbar__crumb">{crumb}</div> : null}
      </div>
      <div className="topbar__spacer"/>

      <div className="search">
        <Icon name="search" size={15}/>
        <input
          placeholder="ค้นหาเลขที่ใบเบิก, ผู้ขอเบิก, เหตุผล..."
          value={search}
          onChange={e => setSearch(e.target.value)}
        />
      </div>

      <div ref={notifRef} style={{position: 'relative'}}>
        <button className="icon-btn" onClick={() => setNotifOpen(o=>!o)}>
          <Icon name="bell" size={18}/>
          <span className="dot"></span>
        </button>
        {notifOpen && (
          <div className="menu" style={{minWidth: 320}}>
            <div className="menu__head">การแจ้งเตือน (3)</div>
            <div className="menu__item">
              <div style={{width: 8, height: 8, borderRadius: '50%', background: 'var(--orange)'}}/>
              <div style={{flex: 1}}>
                <div style={{fontWeight: 600, fontSize: 12.5}}>คำขอ PCR-2026-0428 รออนุมัติ</div>
                <div style={{fontSize: 11.5, color: 'var(--text-muted)'}}>ผู้อำนวยการ • 2 ชั่วโมงที่แล้ว</div>
              </div>
            </div>
            <div className="menu__item">
              <div style={{width: 8, height: 8, borderRadius: '50%', background: 'var(--ok)'}}/>
              <div style={{flex: 1}}>
                <div style={{fontWeight: 600, fontSize: 12.5}}>PCR-2026-0431 ได้รับการอนุมัติ</div>
                <div style={{fontSize: 11.5, color: 'var(--text-muted)'}}>วันนี้ 10:30</div>
              </div>
            </div>
            <div className="menu__item">
              <div style={{width: 8, height: 8, borderRadius: '50%', background: 'var(--warn)'}}/>
              <div style={{flex: 1}}>
                <div style={{fontWeight: 600, fontSize: 12.5}}>PCR-2026-0425 ใกล้ครบกำหนดเคลียร์</div>
                <div style={{fontSize: 11.5, color: 'var(--text-muted)'}}>เหลือ 3 วัน</div>
              </div>
            </div>
          </div>
        )}
      </div>

      <div ref={menuRef} style={{position: 'relative'}}>
        <button className="role-pill" onClick={() => setMenuOpen(o=>!o)}>
          <div className="avatar sm">{user.initials}</div>
          <div style={{display: 'flex', flexDirection: 'column', lineHeight: 1.2, alignItems: 'flex-start'}}>
            <span style={{fontSize: 12.5}}>{user.name.split(' ')[0]}</span>
            <span className="role-pill__role">{ROLE_META[user.role].label}</span>
          </div>
          <Icon name="chevDown" size={14}/>
        </button>
        {menuOpen && (
          <div className="menu">
            <div className="menu__head">สลับมุมมอง role (สำหรับ Demo)</div>
            {Object.entries(ROLE_META).map(([k, v]) => (
              <div key={k} className={`menu__item ${user.role === k ? 'active' : ''}`} onClick={() => { onSwitchRole(k); setMenuOpen(false); }}>
                <Icon name={k === 'staff' ? 'user' : k === 'finance' ? 'wallet' : 'users'} size={15}/>
                <div style={{flex: 1}}>
                  <div style={{fontWeight: 600}}>{v.label}</div>
                  <div style={{fontSize: 11, color: 'var(--text-muted)'}}>{v.en}</div>
                </div>
                {user.role === k && <Icon name="check" size={14}/>}
              </div>
            ))}
            <div className="menu__sep"/>
            <div className="menu__item" onClick={() => setMenuOpen(false)}>
              <Icon name="settings" size={15}/>
              <span>ตั้งค่า</span>
            </div>
            <div className="menu__item" onClick={() => setMenuOpen(false)}>
              <Icon name="logout" size={15}/>
              <span>ออกจากระบบ</span>
            </div>
          </div>
        )}
      </div>
    </header>
  );
}

// ---------- Toast ----------
function Toast({ msg, onClose }) {
  useEffect(() => {
    if (!msg) return;
    const t = setTimeout(onClose, 3200);
    return () => clearTimeout(t);
  }, [msg]);
  if (!msg) return null;
  return (
    <div className="toast">
      <Icon name="checkCircle" size={17} className="ok"/>
      <span>{msg}</span>
    </div>
  );
}

// ---------- Line items editor (Request) ----------
function LineItemsRequest({ items, onChange, readOnly }) {
  const update = (i, key, val) => {
    const next = items.slice();
    next[i] = { ...next[i], [key]: key === 'amount' ? val.replace(/[^\d.]/g, '') : val };
    onChange(next);
  };
  const add = () => onChange([...items, { desc: '', amount: '' }]);
  const remove = (i) => onChange(items.filter((_, idx) => idx !== i));
  return (
    <div className="line-items">
      <div className="li-row head">
        <div className="li-cell li-cell__num">#</div>
        <div className="li-cell">รายการ</div>
        <div className="li-cell" style={{justifyContent: 'flex-end'}}>จำนวนเงิน (บาท)</div>
        <div className="li-cell"></div>
      </div>
      {items.map((it, i) => (
        <div className="li-row" key={i}>
          <div className="li-cell li-cell__num">{i+1}</div>
          <div className="li-cell">
            <input
              placeholder="คำอธิบายรายการ เช่น ค่าเช่าสถานที่ ค่าอาหาร..."
              value={it.desc}
              onChange={e => update(i, 'desc', e.target.value)}
              readOnly={readOnly}
            />
          </div>
          <div className="li-cell">
            <input
              className="money"
              placeholder="0.00"
              value={it.amount}
              onChange={e => update(i, 'amount', e.target.value)}
              readOnly={readOnly}
            />
          </div>
          <div className="li-cell li-cell__del">
            {!readOnly && items.length > 1 && (
              <button onClick={() => remove(i)} title="ลบรายการ">
                <Icon name="trash" size={15}/>
              </button>
            )}
          </div>
        </div>
      ))}
      {!readOnly && (
        <button className="li-add" onClick={add}>
          <Icon name="plus" size={14}/>
          เพิ่มรายการ
        </button>
      )}
    </div>
  );
}

// ---------- Line items editor (Clearing) ----------
function LineItemsClearing({ items, onChange, readOnly }) {
  const update = (i, key, val) => {
    const next = items.slice();
    next[i] = { ...next[i], [key]: ['amount','actual'].includes(key) ? val.replace(/[^\d.]/g, '') : val };
    onChange(next);
  };
  const add = () => onChange([...items, { desc: '', amount: '', actual: '' }]);
  const remove = (i) => onChange(items.filter((_, idx) => idx !== i));
  return (
    <div className="line-items">
      <div className="li-row li-row--clearing head">
        <div className="li-cell li-cell__num">#</div>
        <div className="li-cell">รายการ</div>
        <div className="li-cell" style={{justifyContent: 'flex-end'}}>เบิกไป (บาท)</div>
        <div className="li-cell" style={{justifyContent: 'flex-end'}}>ใช้จริง (บาท)</div>
        <div className="li-cell"></div>
      </div>
      {items.map((it, i) => (
        <div className="li-row li-row--clearing" key={i}>
          <div className="li-cell li-cell__num">{i+1}</div>
          <div className="li-cell">
            <input
              placeholder="คำอธิบายรายการ"
              value={it.desc}
              onChange={e => update(i, 'desc', e.target.value)}
              readOnly={readOnly}
            />
          </div>
          <div className="li-cell">
            <input
              className="money"
              placeholder="0.00"
              value={it.amount}
              onChange={e => update(i, 'amount', e.target.value)}
              readOnly={readOnly}
            />
          </div>
          <div className="li-cell">
            <input
              className="money"
              placeholder="0.00"
              value={it.actual}
              onChange={e => update(i, 'actual', e.target.value)}
              readOnly={readOnly}
            />
          </div>
          <div className="li-cell li-cell__del">
            {!readOnly && items.length > 1 && (
              <button onClick={() => remove(i)}><Icon name="trash" size={15}/></button>
            )}
          </div>
        </div>
      ))}
      {!readOnly && (
        <button className="li-add" onClick={add}>
          <Icon name="plus" size={14}/> เพิ่มรายการ
        </button>
      )}
    </div>
  );
}

// ---------- Receipts ----------
const SAMPLE_RECEIPT_NAMES = [
  'receipt-hotel-marriott.pdf',
  'taxi-bolt-2026-05-08.jpg',
  'lunch-true-coffee.jpg',
  'fuel-shell-2026-05-09.pdf',
  'venue-impact-arena.pdf',
  'stationery-officemate.jpg',
];

function Receipts({ files, onChange, readOnly }) {
  const inputRef = useRef();
  const add = () => {
    // mock — picks a random sample
    const pool = SAMPLE_RECEIPT_NAMES.filter(n => !files.find(f => f.name === n));
    if (pool.length === 0) return;
    const pick = pool[Math.floor(Math.random() * pool.length)];
    const size = (Math.random() * 1.8 + 0.2).toFixed(1) + ' MB';
    const isImg = pick.endsWith('.jpg') || pick.endsWith('.png');
    onChange([...files, { name: pick, size, kind: isImg ? 'image' : 'pdf' }]);
  };
  const remove = (i) => onChange(files.filter((_, idx) => idx !== i));
  return (
    <div>
      {!readOnly && (
        <div className="dropzone" onClick={add}>
          <Icon name="upload" size={26}/>
          <b>คลิกเพื่อแนบใบเสร็จ หรือลากไฟล์มาวางที่นี่</b>
          <span>รองรับ JPG, PNG, PDF ขนาดไม่เกิน 10MB ต่อไฟล์</span>
        </div>
      )}
      {files.length > 0 && (
        <div className="receipts">
          {files.map((f, i) => (
            <div className="receipt" key={i}>
              <div className="receipt__thumb">
                <Icon name={f.kind === 'image' ? 'image' : 'fileText'} size={16}/>
              </div>
              <div className="receipt__meta">
                <b>{f.name}</b>
                <span>{f.size}</span>
              </div>
              {!readOnly && (
                <button className="receipt__del" onClick={() => remove(i)}>
                  <Icon name="x" size={14}/>
                </button>
              )}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ---------- Approval Timeline ----------
function ApprovalTimeline({ record }) {
  const steps = [
    { key: 'submit',  label: 'ยื่นคำขอ',          role: 'staff'    },
    { key: 'manager', label: 'ผู้จัดการฝ่ายอนุมัติ', role: 'manager'  },
    { key: 'director',label: 'ผู้อำนวยการอนุมัติ',  role: 'director' },
    { key: 'finance', label: 'การเงินตรวจสอบ',     role: 'finance'  },
    { key: 'paid',    label: 'จ่ายเงิน',           role: 'finance'  },
  ];

  // Derive done set from timeline
  const tl = record.timeline || [];
  const submitT = tl.find(t => t.type === 'submit');
  const mgrT    = tl.find(t => t.type === 'approve' && t.role === 'manager');
  const dirT    = tl.find(t => t.type === 'approve' && t.role === 'director');
  const finT    = tl.find(t => t.type === 'approve' && t.role === 'finance');
  const paidT   = tl.find(t => t.type === 'paid');
  const rejT    = tl.find(t => t.type === 'reject');

  const events = [
    { step: steps[0], event: submitT, done: !!submitT },
    { step: steps[1], event: mgrT,    done: !!mgrT,    reject: rejT && rejT.role === 'manager' ? rejT : null },
    { step: steps[2], event: dirT,    done: !!dirT,    reject: rejT && rejT.role === 'director' ? rejT : null },
    { step: steps[3], event: finT,    done: !!finT,    reject: rejT && rejT.role === 'finance' ? rejT : null },
    { step: steps[4], event: paidT,   done: !!paidT },
  ];

  // current
  const currentIdx = (() => {
    if (record.status === 'rejected') return events.findIndex(e => e.reject);
    if (record.status === 'pending_mgr') return 1;
    if (record.status === 'pending_dir') return 2;
    if (record.status === 'pending_fin') return 3;
    if (record.status === 'approved') return 4;
    if (record.status === 'paid' || record.status === 'clearing' || record.status === 'cleared') return -1; // all done
    return -1;
  })();

  return (
    <div className="timeline">
      {events.map((e, i) => {
        let dotState = 'wait';
        let dotIcon = null;
        if (e.reject) { dotState = 'reject'; dotIcon = <Icon name="x" size={14}/>; }
        else if (e.done) { dotState = 'done'; dotIcon = <Icon name="check" size={14}/>; }
        else if (i === currentIdx) { dotState = 'active'; dotIcon = <Icon name="clock" size={14}/>; }
        else { dotIcon = <Icon name="clock" size={13}/>; }
        const ev = e.reject || e.event;
        return (
          <div className="tl-row" key={i}>
            <div className={`tl-dot ${dotState}`}>{dotIcon}</div>
            <div className="tl-body">
              <div className="tl-body__title">
                {e.step.label}
                {dotState === 'active' && <span className="badge badge--pending"><span className="dot"/>กำลังรอ</span>}
              </div>
              {ev ? (
                <>
                  <div className="tl-body__meta">
                    {ev.who?.name || '—'} · {ROLE_META[ev.who?.role || e.step.role]?.label} · {fmtDateTime(ev.at)}
                  </div>
                  {ev.note ? <div className={`tl-body__note ${e.reject ? 'reject' : ''}`}>{e.reject ? 'เหตุผล: ' : ''}{ev.note}</div> : null}
                </>
              ) : (
                <div className="tl-body__meta">{i === currentIdx ? 'รอการดำเนินการ' : 'ยังไม่ถึงขั้นตอน'}</div>
              )}
            </div>
          </div>
        );
      })}
    </div>
  );
}

// ---------- Empty state ----------
function Empty({ icon='inbox', title='ไม่มีข้อมูล', desc='', action=null }) {
  return (
    <div className="empty">
      <div className="empty__icon"><Icon name={icon} size={22}/></div>
      <h3>{title}</h3>
      {desc && <p>{desc}</p>}
      {action}
    </div>
  );
}

Object.assign(window, {
  Sidebar, Topbar, Toast,
  LineItemsRequest, LineItemsClearing,
  Receipts, ApprovalTimeline, Empty,
  useOnClickOutside,
});
