// ui.jsx — UROSYS shared primitives. Exports to window.
const T = {
  blue: '#0A4FA3', blue600: '#073C7E', blueSurface: '#E8F0FA', blueLine: '#C2D7EE',
  navy: '#003B7E', cyan: '#00A0E0',
  up: '#D8232A', upS: '#FBEAEA', down: '#1F6FD0', downS: '#E9F1FB',
  ok: '#11865B', okS: '#E4F4EC', okL: '#BCE3CF',
  warn: '#D9822B', warnS: '#FBEFDD', warnL: '#F0D2A4',
  alert: '#C8363C', alertS: '#FBE8E8', alertL: '#F0C2C2',
  info: '#1F6FB2', infoS: '#E6F1F9',
  c900: '#0F1722', c800: '#1B2533', c700: '#2B3848', c600: '#475569', c500: '#64748B',
  c400: '#94A3B8', c300: '#CBD5E1', c250: '#DCE3EC', c200: '#E6EBF1', c150: '#EEF2F6',
  c100: '#F4F6F8', c50: '#F9FBFC', white: '#fff', line: '#E6EBF1',
  font: '"Pretendard",-apple-system,system-ui,sans-serif',
  mono: '"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,monospace'
};
const STATUS = {
  ok: { fg: T.ok, bg: T.okS, line: T.okL },
  warn: { fg: T.warn, bg: T.warnS, line: T.warnL },
  alert: { fg: T.alert, bg: T.alertS, line: T.alertL },
  info: { fg: T.info, bg: T.infoS, line: '#CDE3F1' },
  neutral: { fg: T.c600, bg: T.c150, line: T.c200 },
  blue: { fg: T.blue600, bg: T.blueSurface, line: T.blueLine }
};

function Card({ children, style = {}, pad = 0 }) {
  return <div style={{ background: T.white, border: '1px solid ' + T.line, borderRadius: 12, boxShadow: '0 1px 2px rgba(15,23,34,.04)', padding: pad, ...style }}>{children}</div>;
}
function CardHead({ title, sub, reg, right, icon }) {
  return (
    <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12, padding: '15px 18px', borderBottom: '1px solid ' + T.line }}>
      {icon && <div style={{ width: 30, height: 30, borderRadius: 8, background: T.c100, display: 'flex', alignItems: 'center', justifyContent: 'center', color: T.c600, flex: 'none', marginTop: 1 }}><Icon name={icon} size={17} /></div>}
      <div style={{ minWidth: 0 }}>
        <div style={{ fontFamily: T.font, fontWeight: 700, fontSize: 15, color: T.c900, letterSpacing: '-.01em', textAlign: "left" }}>{title}</div>
        {sub && <div style={{ fontFamily: T.font, fontWeight: 500, fontSize: 12, color: T.c500, marginTop: 2 }}>{sub}</div>}
      </div>
      <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 10 }}>
        {reg && <RegTag>{reg}</RegTag>}
        {right}
      </div>
    </div>);

}
function RegTag({ children }) {
  return <span style={{ fontFamily: T.mono, fontSize: 10.5, color: T.c400, background: T.c100, border: '1px solid ' + T.line, borderRadius: 5, padding: '3px 7px', whiteSpace: 'nowrap' }}>{children}</span>;
}
function Pill({ kind = 'neutral', children, dot, icon, small }) {
  const s = STATUS[kind];
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, background: s.bg, color: s.fg, border: '1px solid ' + s.line,
      borderRadius: 999, padding: small ? '2px 8px' : '3px 10px', fontFamily: T.font, fontWeight: 700, fontSize: small ? 10.5 : 11.5, whiteSpace: 'nowrap' }}>
      {dot && <span style={{ width: 6, height: 6, borderRadius: 999, background: s.fg }} />}
      {icon && <Icon name={icon} size={12} stroke={2.2} />}
      {children}
    </span>);

}
function Btn({ children, variant = 'primary', icon, iconR, onClick, size = 'md', style = {}, disabled }) {
  const pad = size === 'sm' ? '6px 11px' : size === 'lg' ? '11px 18px' : '8px 14px';
  const fs = size === 'sm' ? 12.5 : 13.5;
  const v = {
    primary: { background: T.blue, color: '#fff', border: '1px solid ' + T.blue },
    secondary: { background: T.white, color: T.c700, border: '1px solid ' + T.c250 },
    ghost: { background: 'transparent', color: T.c600, border: '1px solid transparent' },
    danger: { background: T.alert, color: '#fff', border: '1px solid ' + T.alert },
    dark: { background: T.c800, color: '#fff', border: '1px solid ' + T.c800 }
  }[variant];
  return (
    <button onClick={disabled ? undefined : onClick} disabled={disabled} style={{
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 6, borderRadius: 8, cursor: disabled ? 'not-allowed' : 'pointer',
      padding: pad, fontFamily: T.font, fontWeight: 600, fontSize: fs, opacity: disabled ? .5 : 1, transition: 'filter .12s', ...v, ...style }}
    onMouseDown={(e) => !disabled && (e.currentTarget.style.filter = 'brightness(.95)')}
    onMouseUp={(e) => e.currentTarget.style.filter = 'none'} onMouseLeave={(e) => e.currentTarget.style.filter = 'none'}>
      {icon && <Icon name={icon} size={15} stroke={2} />}{children}{iconR && <Icon name={iconR} size={15} stroke={2} />}
    </button>);

}
function Segmented({ options, value, onChange, size = 'md' }) {
  return (
    <div style={{ display: 'inline-flex', background: T.c100, border: '1px solid ' + T.line, borderRadius: 9, padding: 3, gap: 2 }}>
      {options.map((o) => {
        const v = typeof o === 'string' ? o : o.v,l = typeof o === 'string' ? o : o.l;
        const on = v === value;
        return <button key={v} onClick={() => onChange(v)} style={{ border: 0, cursor: 'pointer', borderRadius: 7,
          padding: size === 'sm' ? '5px 11px' : '6px 14px', fontFamily: T.font, fontWeight: 600, fontSize: size === 'sm' ? 12 : 12.5,
          background: on ? T.white : 'transparent', color: on ? T.c900 : T.c500, boxShadow: on ? '0 1px 2px rgba(15,23,34,.1)' : 'none' }}>{l}</button>;
      })}
    </div>);

}
function Tabs({ options, value, onChange }) {
  return (
    <div style={{ display: 'flex', gap: 24, borderBottom: '1px solid ' + T.line }}>
      {options.map((o) => {
        const v = typeof o === 'string' ? o : o.v,l = typeof o === 'string' ? o : o.l,c = typeof o === 'object' ? o.count : null;
        const on = v === value;
        return <button key={v} onClick={() => onChange(v)} style={{ border: 0, background: 'none', cursor: 'pointer', position: 'relative',
          padding: '0 0 12px', fontFamily: T.font, fontWeight: on ? 700 : 600, fontSize: 13.5, color: on ? T.c900 : T.c500, display: 'flex', alignItems: 'center', gap: 7 }}>
          {l}{c != null && <span style={{ fontFamily: T.font, fontWeight: 700, fontSize: 11, color: on ? T.blue : T.c400, background: on ? T.blueSurface : T.c100, borderRadius: 999, padding: '1px 7px' }}>{c}</span>}
          {on && <span style={{ position: 'absolute', left: 0, right: 0, bottom: -1, height: 2, background: T.blue, borderRadius: 2 }} />}
        </button>;
      })}
    </div>);

}
// KPI stat
function Stat({ label, value, unit, sub, kind, reg }) {
  return (
    <div style={{ padding: '2px 0' }}>
      <div style={{ fontFamily: T.font, fontWeight: 600, fontSize: 11.5, color: T.c500, letterSpacing: '.02em', textTransform: 'uppercase' }}>{label}</div>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 5, marginTop: 6 }}>
        <span className="num" style={{ fontFamily: T.font, fontWeight: 700, fontSize: 24, color: kind ? STATUS[kind].fg : T.c900, letterSpacing: '-.02em' }}>{value}</span>
        {unit && <span style={{ fontFamily: T.font, fontWeight: 600, fontSize: 13, color: T.c400 }}>{unit}</span>}
      </div>
      {sub && <div style={{ fontFamily: T.font, fontWeight: 500, fontSize: 12, color: T.c500, marginTop: 4 }}>{sub}</div>}
    </div>);

}
// Maker-Checker workflow bar
function MakerChecker({ state = 'approved', maker, checker }) {
  const steps = [
  { k: 'draft', l: 'Draft' }, { k: 'submitted', l: 'Maker submitted' },
  { k: 'review', l: 'Checker review' }, { k: 'approved', l: 'Approved' }];

  const idx = steps.findIndex((s) => s.k === state);
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 0, flexWrap: 'wrap' }}>
      {steps.map((s, i) => {
        const done = i <= idx,cur = i === idx;
        return (
          <React.Fragment key={s.k}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
              <span style={{ width: 20, height: 20, borderRadius: 999, display: 'flex', alignItems: 'center', justifyContent: 'center',
                background: done ? cur ? T.blue : T.ok : T.c150, color: done ? '#fff' : T.c400, fontFamily: T.font, fontWeight: 700, fontSize: 11 }}>
                {done && !cur ? <Icon name="check" size={12} stroke={3} color="#fff" /> : i + 1}
              </span>
              <span style={{ fontFamily: T.font, fontWeight: cur ? 700 : 600, fontSize: 12, color: done ? T.c800 : T.c400 }}>{s.l}</span>
            </div>
            {i < steps.length - 1 && <span style={{ width: 28, height: 2, background: i < idx ? T.ok : T.c200, margin: '0 10px', borderRadius: 2 }} />}
          </React.Fragment>);

      })}
    </div>);

}
// Data table — cols:[{k,t,w,num,align}], rows:[{...cells,_click,_total,_open}]
function Table({ cols, rows, dense }) {
  const cellPad = dense ? '9px 14px' : '12px 16px';
  return (
    <div style={{ overflowX: 'auto' }}>
      <table style={{ width: '100%', borderCollapse: 'collapse', fontFamily: T.font }}>
        <thead>
          <tr>{cols.map((c) =>
            <th key={c.k} style={{ width: c.w, textAlign: c.num ? 'right' : c.align || 'left', padding: '10px 16px', borderBottom: '1px solid ' + T.line,
              background: T.c50, fontFamily: T.font, fontWeight: 700, fontSize: 11, color: T.c500, letterSpacing: '.03em', textTransform: 'uppercase', whiteSpace: 'nowrap', position: 'sticky', top: 0 }}>{c.t}</th>
            )}</tr>
        </thead>
        <tbody>
          {rows.map((r, i) =>
          <tr key={i} onClick={r._click} style={{ cursor: r._click ? 'pointer' : 'default', background: r._total ? T.c50 : 'transparent' }}
          onMouseEnter={(e) => {if (r._click) e.currentTarget.style.background = T.c50;}}
          onMouseLeave={(e) => {if (r._click) e.currentTarget.style.background = r._total ? T.c50 : 'transparent';}}>
              {cols.map((c) =>
            <td key={c.k} style={{ width: c.w, textAlign: c.num ? 'right' : c.align || 'left', padding: cellPad,
              borderBottom: i < rows.length - 1 ? '1px solid ' + T.c150 : 'none', fontFamily: c.num ? T.font : T.font,
              fontVariantNumeric: c.num ? 'tabular-nums' : 'normal', fontWeight: r._total ? 700 : 500, fontSize: 13, color: T.c700, whiteSpace: 'nowrap', verticalAlign: 'middle' }}>{r[c.k]}</td>
            )}
            </tr>
          )}
        </tbody>
      </table>
    </div>);

}
Object.assign(window, { T, STATUS, Card, CardHead, RegTag, Pill, Btn, Segmented, Tabs, Stat, MakerChecker, Table });

// ---- IBK additions ----
// status -> pill kind ; 정상 ok(green) / 유보 neutral(gray) / 주의 warn(orange) / 위험 alert(red)
const STKIND = { '정상': 'ok', '안전': 'ok', '적정': 'blue', '유보': 'neutral', '주의': 'warn', '위험': 'alert' };
function StatusPill({ status, small }) {
  return <Pill kind={STKIND[status] || 'neutral'} small={small} dot>{status}</Pill>;
}
// directional number (KR convention: + red / − blue)
function dirColor(v) {return v > 0 ? T.up : v < 0 ? T.down : T.c500;}
function Delta({ v, suffix = '', digits = 2, arrow = true, size = 12.5 }) {
  const c = dirColor(v);const s = v > 0 ? '+' : '';
  return <span className="num" style={{ fontFamily: T.font, fontWeight: 700, fontSize: size, color: c, display: 'inline-flex', alignItems: 'center', gap: 2 }}>
    {arrow && v !== 0 && <Icon name={v > 0 ? 'trendUp' : 'trendDown'} size={size} stroke={2.4} color={c} />}{s}{v.toFixed(digits)}{suffix}</span>;
}
// search box
function Search({ value, onChange, placeholder = '검색', w = 240 }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 8, background: T.white, border: '1px solid ' + T.c250, borderRadius: 8, padding: '7px 11px', width: w }}>
      <Icon name="search" size={15} color={T.c400} />
      <input value={value} onChange={(e) => onChange(e.target.value)} placeholder={placeholder}
      style={{ border: 0, outline: 'none', flex: 1, minWidth: 0, fontFamily: T.font, fontWeight: 500, fontSize: 12.5, color: T.c800, background: 'transparent' }} />
      {value && <button onClick={() => onChange('')} style={{ border: 0, background: 'none', cursor: 'pointer', color: T.c400, display: 'flex', padding: 0 }}><Icon name="x" size={14} /></button>}
    </div>);

}
// filter chips (single-select)
function Chips({ options, value, onChange }) {
  return (
    <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
      {options.map((o) => {const v = typeof o === 'string' ? o : o.v,l = typeof o === 'string' ? o : o.l,c = typeof o === 'object' ? o.count : null;const on = v === value;
        return <button key={v} onClick={() => onChange(v)} style={{ border: '1px solid ' + (on ? T.blue : T.c250), cursor: 'pointer', borderRadius: 999,
          padding: '5px 12px', fontFamily: T.font, fontWeight: on ? 700 : 600, fontSize: 12, color: on ? '#fff' : T.c600, background: on ? T.blue : T.white, display: 'flex', alignItems: 'center', gap: 6 }}>
          {l}{c != null && <span style={{ fontWeight: 700, fontSize: 10.5, color: on ? 'rgba(255,255,255,.85)' : T.c400 }}>{c}</span>}</button>;
      })}
    </div>);

}
// sortable data table. cols:[{k,t,w,num,align,render(row),sortVal(row)}]. sortable headers toggle.
function DataTable({ cols, rows, initialSort, dense, onRow, maxH }) {
  const [sort, setSort] = React.useState(initialSort || { k: null, dir: 'desc' });

  // cols를 ref로 관리 — 인라인 배열이 매 렌더마다 새 참조를 만들어도
  // useMemo 의존성에서 제외해 불필요한 재정렬을 막음
  const colsRef = React.useRef(cols);
  colsRef.current = cols;

  const sorted = React.useMemo(() => {
    if (!sort.k) return rows;
    const col = colsRef.current.find((c) => c.k === sort.k);
    if (!col) return rows;
    const val = col.sortVal || ((r) => r[sort.k]);
    const INF = sort.dir === 'asc' ? Infinity : -Infinity;
    return [...rows].sort((a, b) => {
      let x = val(a), y = val(b);
      // null/undefined → 항상 맨 아래
      if (x == null && y == null) return 0;
      if (x == null) return 1;
      if (y == null) return -1;
      if (typeof x === 'string') return sort.dir === 'asc' ? x.localeCompare(y) : y.localeCompare(x);
      return sort.dir === 'asc' ? x - y : y - x;
    });
  }, [rows, sort]); // cols 제외 — colsRef로 최신값 참조

  const cellPad = dense ? '9px 13px' : '11px 15px';

  // c.k(문자열)만 전달해 클로저 stale 문제 방지
  const handleClick = React.useCallback((k, sortable) => {
    if (!sortable) return;
    setSort((s) => s.k === k ? { k, dir: s.dir === 'asc' ? 'desc' : 'asc' } : { k, dir: 'desc' });
  }, []);

  return (
    <div style={{ overflow: 'auto', maxHeight: maxH }}>
      <table style={{ width: '100%', borderCollapse: 'collapse', fontFamily: T.font }}>
        <thead>
          <tr>{cols.map((c) => {
            const active   = sort.k === c.k;
            const sortable = c.sortable !== false;
            return (
              <th key={c.k} onClick={() => handleClick(c.k, sortable)}
                style={{ width: c.w, textAlign: c.num ? 'right' : c.align || 'left',
                  padding: '10px 15px', borderBottom: '1px solid ' + T.line,
                  background: T.c50, fontFamily: T.font, fontWeight: 700, fontSize: 10.5,
                  color: active ? T.blue : T.c500, letterSpacing: '.03em',
                  textTransform: 'uppercase', whiteSpace: 'nowrap',
                  position: 'sticky', top: 0,
                  cursor: sortable ? 'pointer' : 'default', userSelect: 'none', zIndex: 1 }}>
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, flexDirection: c.num ? 'row-reverse' : 'row' }}>
                  {c.t}
                  {sortable && (
                    <Icon name={active ? (sort.dir === 'asc' ? 'chevUp' : 'chevDown') : 'sort'}
                      size={12} color={active ? T.blue : T.c300} stroke={2.2} />
                  )}
                </span>
              </th>
            );
          })}</tr>
        </thead>
        <tbody>
          {sorted.map((r, i) => (
            <tr key={r._key || i} onClick={onRow ? () => onRow(r) : undefined}
              style={{ cursor: onRow ? 'pointer' : 'default' }}
              onMouseEnter={(e) => { if (onRow) e.currentTarget.style.background = T.c50; }}
              onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; }}>
              {cols.map((c) => (
                <td key={c.k} style={{ textAlign: c.num ? 'right' : c.align || 'left',
                  padding: cellPad,
                  borderBottom: i < sorted.length - 1 ? '1px solid ' + T.c150 : 'none',
                  fontVariantNumeric: c.num ? 'tabular-nums' : 'normal',
                  fontWeight: 500, fontSize: 12.5, color: T.c700,
                  whiteSpace: 'nowrap', verticalAlign: 'middle' }}>
                  {c.render ? c.render(r) : r[c.k]}
                </td>
              ))}
            </tr>
          ))}
          {sorted.length === 0 && (
            <tr><td colSpan={cols.length} style={{ padding: '40px', textAlign: 'center',
              fontFamily: T.font, fontWeight: 500, fontSize: 13, color: T.c400 }}>
              검색 결과가 없어요.
            </td></tr>
          )}
        </tbody>
      </table>
    </div>);
}
Object.assign(window, { STKIND, StatusPill, dirColor, Delta, Search, Chips, DataTable });
