// ui.jsx — shared primitives for RAlly
// Icons inline as SVGs (lucide-style). Stroke 1.75, currentColor.

const Icon = ({ name, size = 16, stroke = 1.75, ...rest }) => {
  const paths = ICONS[name];
  if (!paths) return null;
  return (
    <svg
      width={size} height={size} viewBox="0 0 24 24"
      fill="none" stroke="currentColor"
      strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"
      {...rest}
    >
      {paths}
    </svg>
  );
};

const ICONS = {
  flag: <><path d="M4 21V4"/><path d="M4 4h11l-2 4 2 4H4"/></>,
  run: <><circle cx="13" cy="4" r="2"/><path d="M4 22l3-8 5 1 2-4"/><path d="M7 14l3-3 4 1 2 5 4-1"/></>,
  trophy: <><path d="M8 21h8M12 17v4M7 4h10v5a5 5 0 0 1-10 0V4z"/><path d="M17 4h3v2a3 3 0 0 1-3 3M7 4H4v2a3 3 0 0 0 3 3"/></>,
  heart: <><path d="M3 12h4l2-5 4 10 2-5h6"/></>,
  search: <><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></>,
  bell: <><path d="M6 8a6 6 0 1 1 12 0c0 7 3 7 3 9H3c0-2 3-2 3-9z"/><path d="M10 21a2 2 0 0 0 4 0"/></>,
  plus: <><path d="M12 5v14M5 12h14"/></>,
  check: <><path d="M20 6L9 17l-5-5"/></>,
  x: <><path d="M18 6L6 18M6 6l12 12"/></>,
  alert: <><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></>,
  alert_circle: <><circle cx="12" cy="12" r="10"/><path d="M12 8v4M12 16h.01"/></>,
  info: <><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></>,
  sparkles: <><path d="M12 3l1.7 5 5 1.7-5 1.7L12 16l-1.7-5-5-1.7 5-1.7L12 3z"/><path d="M19 14l.7 2 2 .7-2 .7L19 19l-.7-1.7-2-.7 2-.7L19 14z"/></>,
  file: <><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></>,
  folder: <><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7z"/></>,
  dots: <><circle cx="6" cy="12" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="18" cy="12" r="1.5"/></>,
  arrow_right: <><path d="M5 12h14M13 5l7 7-7 7"/></>,
  chev_right: <><path d="M9 6l6 6-6 6"/></>,
  chev_down: <><path d="M6 9l6 6 6-6"/></>,
  chev_up: <><path d="M6 15l6-6 6 6"/></>,
  download: <><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M7 10l5 5 5-5M12 15V3"/></>,
  share: <><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="M8.6 13.5l6.8 4M15.4 6.5L8.6 10.5"/></>,
  eye: <><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></>,
  edit: <><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.1 2.1 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></>,
  copy: <><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></>,
  trash: <><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></>,
  link: <><path d="M10 13a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-1 1"/><path d="M14 11a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l1-1"/></>,
  list: <><path d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01"/></>,
  grid: <><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></>,
  bold: <><path d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"/><path d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"/></>,
  italic: <><path d="M19 4h-9M14 20H5M15 4L9 20"/></>,
  underline: <><path d="M6 3v7a6 6 0 0 0 12 0V3M4 21h16"/></>,
  h1: <><path d="M4 12h8M4 18V6M12 18V6"/><path d="M17 12l3-2v8"/></>,
  h2: <><path d="M4 12h8M4 18V6M12 18V6"/><path d="M17 10h4l-4 5h4"/></>,
  table: <><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M3 15h18M9 3v18M15 3v18"/></>,
  filter: <><path d="M22 3H2l8 9.5V19l4 2v-8.5L22 3z"/></>,
  user: <><circle cx="12" cy="8" r="4"/><path d="M4 21v-2a4 4 0 0 1 4-4h8a4 4 0 0 1 4 4v2"/></>,
  users: <><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"/></>,
  calendar: <><rect x="3" y="4" width="18" height="18" rx="2"/><path d="M16 2v4M8 2v4M3 10h18"/></>,
  message: <><path d="M21 11.5a8.4 8.4 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.4 8.4 0 0 1-3.8-.9L3 21l1.9-5.7a8.4 8.4 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.4 8.4 0 0 1 3.8-.9h.5a8.5 8.5 0 0 1 8 8v.5z"/></>,
  shield: <><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></>,
  beaker: <><path d="M4.5 3h15M6 3v13l-2 5h16l-2-5V3"/><path d="M6 11h12"/></>,
  package: <><path d="M16.5 9.4L7.5 4.21M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><path d="M3.27 6.96L12 12.01l8.73-5.05M12 22.08V12"/></>,
  layers: <><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5M2 12l10 5 10-5"/></>,
  home: <><path d="M3 12L12 3l9 9M5 10v10h4v-6h6v6h4V10"/></>,
  clock: <><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></>,
  bookmark: <><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z"/></>,
  arrow_up_right: <><path d="M7 17L17 7M7 7h10v10"/></>,
};

window.RAlly = window.RAlly || {};

// ── 데모 모드: ON이면 시드(더미) 데이터 표시, OFF(기본)면 실서비스(실데이터만) ──
window.RAlly.isDemo = () => { try { return localStorage.getItem('RALLY_DEMO') === '1'; } catch (e) { return false; } };
window.RAlly.setDemo = (b) => { try { localStorage.setItem('RALLY_DEMO', b ? '1' : '0'); } catch (e) {} location.reload(); };
// 선택 트랙이 없으면 실제 생성 트랙(profile 보유·최신)을 해석. 시드 트랙 1로 폴백하지 않음.
window.RAlly.resolveTrackId = () => {
  const t = (typeof window !== 'undefined' && window.__RALLY_TRACK);
  if (t) return Promise.resolve(t);
  return fetch('/api/tracks').then((r) => r.json()).then((d) => {
    const ts = d.tracks || [];
    const pick = ts.slice(-1)[0];  // 실모드에선 서버가 실제 트랙만 반환
    const id = pick ? pick.id : null;
    if (id && typeof window !== 'undefined') window.__RALLY_TRACK = id;
    return id;
  }).catch(() => null);
};
// /api/ 요청 공통 처리:
//  · 세션 쿠키 전송(credentials: same-origin) — 서버가 신원·역할·조직을 세션에서 도출한다.
//  · 데모 모드 → demo=1 (서버가 내 회사 + 시드 데이터를 반환)
//  · 401(미인증) → 로그인 화면으로 되돌리는 전역 이벤트 발행
// ※ org_id는 보내더라도 서버가 세션 값으로 덮어쓴다(클라이언트 값 불신). 여긴 보내지 않는다.
(function () {
  if (window.__RALLY_FETCH_PATCHED) return;
  window.__RALLY_FETCH_PATCHED = true;
  const _f = window.fetch.bind(window);
  const AUTH_PATHS = ['/api/auth/login', '/api/auth/me', '/api/auth/logout'];
  window.fetch = (url, opts) => {
    let u = url;
    const o = Object.assign({}, opts || {});
    o.credentials = o.credentials || 'same-origin';   // 세션 쿠키 전송
    try {
      const isGet = !o.method || String(o.method).toUpperCase() === 'GET';
      if (typeof u === 'string' && u.indexOf('/api/') === 0 && isGet
          && window.RAlly.isDemo() && u.indexOf('demo=') < 0) {
        u += (u.indexOf('?') >= 0 ? '&' : '?') + 'demo=1';
      }
    } catch (e) {}
    return _f(u, o).then((res) => {
      try {
        const isAuthPath = typeof u === 'string' && AUTH_PATHS.some((p) => u.indexOf(p) === 0);
        if (res.status === 401 && !isAuthPath) {
          window.RAlly.clearUser();
          window.dispatchEvent(new CustomEvent('rally:unauthorized'));
        }
      } catch (e) {}
      return res;
    });
  };
})();

window.RAlly.Icon = Icon;

// ---------- Pill ----------
const Pill = ({ children, variant = 'default', size, className = '', ...rest }) => {
  const cls = ['pill', variant !== 'default' && `pill--${variant}`, size === 'lg' && 'pill--lg', className]
    .filter(Boolean).join(' ');
  return <span className={cls} {...rest}>{children}</span>;
};

// ---------- Tag (uppercase micro) ----------
const Tag = ({ children, variant, className = '' }) => {
  const cls = ['tag', variant && `tag--${variant}`, className].filter(Boolean).join(' ');
  return <span className={cls}>{children}</span>;
};

// ---------- Avatar ----------
const Avatar = ({ initials, variant, size, title }) => {
  const cls = ['avatar', variant && `avatar--${variant}`, size && `avatar--${size}`].filter(Boolean).join(' ');
  return <span className={cls} title={title}>{initials}</span>;
};

// ---------- Button ----------
const Button = ({ variant = 'ghost', size, icon, iconRight, children, className = '', ...rest }) => {
  const cls = ['btn', `btn--${variant}`, size && `btn--${size}`, className].filter(Boolean).join(' ');
  return (
    <button className={cls} {...rest}>
      {icon && <Icon name={icon} size={15} />}
      {children}
      {iconRight && <Icon name={iconRight} size={15} />}
    </button>
  );
};

// ---------- Progress ----------
const Progress = ({ value, size, onNavy }) => {
  const cls = ['track', size === 'sm' && 'track--sm', onNavy && 'track--on-navy']
    .filter(Boolean).join(' ');
  return <div className={cls}><div className="track__fill" style={{ width: `${value}%` }} /></div>;
};

// ---------- KPI card ----------
const KPI = ({ label, value, valueColor, meta, metaTone }) => (
  <div className="kpi">
    <div className="kpi__label">{label}</div>
    <div className={'kpi__value' + (valueColor === 'coral' ? ' kpi__value--coral' : '')}>{value}</div>
    {meta && <div className={'kpi__meta' + (metaTone ? ' kpi__meta--' + metaTone : '')}>{meta}</div>}
  </div>
);

Object.assign(window.RAlly, { Icon, Pill, Tag, Avatar, Button, Progress, KPI });

// ── 현재 사용자 — 신원의 근거는 서버 세션(HttpOnly 쿠키)이다 ────────────────
// localStorage(rally_user)는 화면 표시용 '캐시'일 뿐 권한의 근거가 아니다.
// 권한·역할·조직 판정은 전부 서버가 세션에서 도출한다(클라이언트 값 불신).
// 데모 계정은 존재하지 않는다 — 실계정(이메일+비밀번호)만 로그인 가능.
window.RAlly.fetchMe = () =>
  fetch('/api/auth/me', { credentials: 'same-origin' })
    .then((r) => (r.ok ? r.json() : null))
    .then((d) => {
      if (d && d.ok && d.user) { window.RAlly.setUser(d.user); return d.user; }
      window.RAlly.clearUser();
      return null;
    })
    .catch(() => null);
window.RAlly.login = (email, password) =>
  fetch('/api/auth/login', {
    method: 'POST', credentials: 'same-origin',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email, password }),
  }).then((r) => r.json().then((d) => ({ status: r.status, data: d })));
window.RAlly.logout = () =>
  fetch('/api/auth/logout', { method: 'POST', credentials: 'same-origin' })
    .catch(() => {})
    .then(() => { window.RAlly.clearUser(); });
window.RAlly.getOrgId = () => {
  const u = window.RAlly.getUser();
  return (u && u.orgId) || 0;
};
window.RAlly.getUser = () => {
  try { return JSON.parse(localStorage.getItem('rally_user')) || null; } catch (e) { return null; }
};

// ── 역할별 문서 담당(개발자=AUTHOR가 작성하는 개발 문서 셋) ──
// 백엔드 doc_role 게이트와 동일 계약. 개발자는 이 문서종만 작성/저장 가능.
window.RAlly.DEV_DOCS = ['DMR', 'SRS', 'SDS', 'SVV', 'SVR', 'TVR', 'VAR', 'TRC', 'ADM', 'AMS', 'APM', 'CSC', 'DIR', 'DOR'];
// 개발자(AUTHOR)면 개발 문서만 허용, 그 외 역할(RA/ADMIN)은 전체 허용.
window.RAlly.canAuthorDoc = (role, docType) =>
  role !== 'AUTHOR' || window.RAlly.DEV_DOCS.includes(docType);
window.RAlly.setUser = (u) => { try { localStorage.setItem('rally_user', JSON.stringify(u)); } catch (e) {} };
window.RAlly.clearUser = () => { try { localStorage.removeItem('rally_user'); } catch (e) {} };
