// 共通コンポーネント
const { useState, useMemo, useEffect, useRef } = React;

function Chip({ kind = "default", children }) {
  const palette = {
    ok: { bg: "#E6F4EC", fg: "#0F7A3E", bd: "#BFE3CD" },
    warn: { bg: "#FFF6DA", fg: "#8A6100", bd: "#F4DC97" },
    danger: { bg: "#FCE4E4", fg: "#A41F1F", bd: "#F2BFBF" },
    muted: { bg: "#EEF1F5", fg: "#5A6679", bd: "#DCE2EB" },
    info: { bg: "#E5EEFC", fg: "#1B4FB3", bd: "#BFD3F2" },
    default: { bg: "#EEF1F5", fg: "#3D4756", bd: "#D8DEE7" },
  };
  const p = palette[kind] || palette.default;
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 4,
      fontSize: 11, lineHeight: "16px", fontWeight: 600,
      padding: "2px 8px", borderRadius: 999,
      background: p.bg, color: p.fg, border: `1px solid ${p.bd}`,
      whiteSpace: "nowrap",
    }}>{children}</span>
  );
}

function StatusChip({ status }) {
  const map = {
    "有効": "ok", "在籍": "ok",
    "期限間近": "warn",
    "期限切れ": "danger", "停止": "danger", "退職": "danger",
    "未紐付": "muted",
  };
  return <Chip kind={map[status] || "default"}>{status}</Chip>;
}

function KpiCard({ label, value, unit, delta, deltaKind = "muted", sub }) {
  return (
    <div style={{
      background: "#fff", border: "1px solid var(--border)", borderRadius: 8,
      padding: "16px 18px", display: "flex", flexDirection: "column", gap: 6,
      minWidth: 0,
    }}>
      <div style={{ fontSize: 12, color: "var(--ink-3)", fontWeight: 500 }}>{label}</div>
      <div style={{ display: "flex", alignItems: "baseline", gap: 6 }}>
        <span style={{ fontSize: 28, fontWeight: 700, color: "var(--ink-1)", fontFamily: "var(--font-num)", letterSpacing: "-0.01em" }}>{value}</span>
        {unit && <span style={{ fontSize: 13, color: "var(--ink-3)", fontWeight: 500 }}>{unit}</span>}
      </div>
      {(delta || sub) && (
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 8 }}>
          {sub && <span style={{ fontSize: 11, color: "var(--ink-3)" }}>{sub}</span>}
          {delta && <Chip kind={deltaKind}>{delta}</Chip>}
        </div>
      )}
    </div>
  );
}

function SectionCard({ title, action, children, padding = true, style = {} }) {
  return (
    <section style={{
      background: "#fff", border: "1px solid var(--border)", borderRadius: 8,
      display: "flex", flexDirection: "column", minWidth: 0, ...style,
    }}>
      <header style={{
        display: "flex", alignItems: "center", justifyContent: "space-between",
        padding: "12px 18px", borderBottom: "1px solid var(--border-soft)",
      }}>
        <h2 style={{ fontSize: 13, fontWeight: 700, color: "var(--ink-1)", margin: 0, letterSpacing: "0.02em" }}>{title}</h2>
        {action}
      </header>
      <div style={padding ? { padding: 18 } : {}}>{children}</div>
    </section>
  );
}

// 横棒グラフ
function BarChart({ data, maxValue, format = (v) => v, color = "var(--accent)" }) {
  const max = maxValue ?? Math.max(...data.map(d => d.value));
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
      {data.map((d, i) => (
        <div key={i} style={{ display: "grid", gridTemplateColumns: "64px 1fr 56px", alignItems: "center", gap: 10 }}>
          <span style={{ fontSize: 12, color: "var(--ink-2)" }}>{d.label}</span>
          <div style={{ height: 8, background: "var(--bg-soft)", borderRadius: 4, overflow: "hidden" }}>
            <div style={{ height: "100%", width: `${(d.value / max) * 100}%`, background: color, borderRadius: 4, transition: "width .4s ease" }} />
          </div>
          <span style={{ fontSize: 12, color: "var(--ink-1)", fontFamily: "var(--font-num)", textAlign: "right", fontWeight: 600 }}>{format(d.value)}</span>
        </div>
      ))}
    </div>
  );
}

// 縦棒グラフ（積み上げ対応）
function ColumnChart({ data, stacks, height = 200, formatY = (v) => v }) {
  // data: [{ label, values: { key: number } }], stacks: [{ key, label, color }]
  const totals = data.map(d => stacks.reduce((s, k) => s + (d.values[k.key] || 0), 0));
  const max = Math.max(...totals) * 1.1;
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
      <div style={{ display: "flex", alignItems: "flex-end", gap: 6, height, padding: "0 4px", borderBottom: "1px solid var(--border-soft)" }}>
        {data.map((d, i) => {
          const total = totals[i];
          const h = (total / max) * height;
          return (
            <div key={i} style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", gap: 4 }}>
              <span style={{ fontSize: 10, color: "var(--ink-3)", fontFamily: "var(--font-num)" }}>{formatY(total)}</span>
              <div style={{ width: "100%", maxWidth: 36, height: h, display: "flex", flexDirection: "column-reverse", borderRadius: "3px 3px 0 0", overflow: "hidden" }}>
                {stacks.map(s => {
                  const v = d.values[s.key] || 0;
                  return <div key={s.key} title={`${s.label}: ${formatY(v)}`} style={{ height: (v / total) * h, background: s.color }} />;
                })}
              </div>
            </div>
          );
        })}
      </div>
      <div style={{ display: "flex", gap: 6, padding: "0 4px" }}>
        {data.map((d, i) => (
          <div key={i} style={{ flex: 1, textAlign: "center", fontSize: 10, color: "var(--ink-3)" }}>{d.label}</div>
        ))}
      </div>
      <div style={{ display: "flex", gap: 14, marginTop: 6, justifyContent: "flex-end" }}>
        {stacks.map(s => (
          <div key={s.key} style={{ display: "flex", alignItems: "center", gap: 5, fontSize: 11, color: "var(--ink-2)" }}>
            <span style={{ width: 10, height: 10, background: s.color, borderRadius: 2 }} />
            {s.label}
          </div>
        ))}
      </div>
    </div>
  );
}

// テーブル
function DataTable({ columns, rows, onRowClick, denseRow = 40, emptyText = "データがありません" }) {
  return (
    <div style={{ width: "100%", overflow: "auto", border: "1px solid var(--border)", borderRadius: 6, background: "#fff" }}>
      <table style={{ width: "100%", borderCollapse: "separate", borderSpacing: 0, fontSize: 12.5 }}>
        <thead style={{ position: "sticky", top: 0, zIndex: 1 }}>
          <tr>
            {columns.map((c, i) => (
              <th key={i} style={{
                background: "#F7F9FC", color: "var(--ink-2)", fontWeight: 600,
                padding: "9px 12px", textAlign: c.align || "left",
                borderBottom: "1px solid var(--border)",
                whiteSpace: "nowrap", fontSize: 11.5, letterSpacing: "0.02em",
                minWidth: c.minWidth, width: c.width,
              }}>{c.title}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {rows.length === 0 ? (
            <tr><td colSpan={columns.length} style={{ padding: 32, textAlign: "center", color: "var(--ink-3)" }}>{emptyText}</td></tr>
          ) : rows.map((r, i) => (
            <tr key={i}
              onClick={onRowClick ? () => onRowClick(r) : undefined}
              style={{
                cursor: onRowClick ? "pointer" : "default",
                background: i % 2 === 0 ? "#fff" : "#FBFCFE",
                height: denseRow,
                transition: "background .12s",
              }}
              onMouseEnter={e => e.currentTarget.style.background = "#EEF4FE"}
              onMouseLeave={e => e.currentTarget.style.background = i % 2 === 0 ? "#fff" : "#FBFCFE"}>
              {columns.map((c, j) => (
                <td key={j} style={{
                  padding: "8px 12px", borderBottom: "1px solid var(--border-soft)",
                  textAlign: c.align || "left", color: "var(--ink-1)",
                  fontFamily: c.numeric ? "var(--font-num)" : "inherit",
                  whiteSpace: c.wrap ? "normal" : "nowrap",
                  fontVariantNumeric: c.numeric ? "tabular-nums" : "normal",
                }}>{c.render ? c.render(r) : r[c.key]}</td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

// アイコン (シンプルなSVG)
const Icon = {
  car: (p) => (<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M5 17h14M5 17l1.5-5h11L19 17M5 17v2a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1v-2M16 17v2a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1v-2"/><circle cx="8" cy="14.5" r="1"/><circle cx="16" cy="14.5" r="1"/></svg>),
  user: (p) => (<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="8" r="3.5"/><path d="M5 20c0-3.5 3-6 7-6s7 2.5 7 6"/></svg>),
  card: (p) => (<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="3" y="6" width="18" height="13" rx="1.5"/><path d="M3 10h18M7 15h4"/></svg>),
  dash: (p) => (<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="3" y="3" width="8" height="8" rx="1"/><rect x="13" y="3" width="8" height="5" rx="1"/><rect x="13" y="10" width="8" height="11" rx="1"/><rect x="3" y="13" width="8" height="8" rx="1"/></svg>),
  coin: (p) => (<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="12" r="8"/><path d="M9 10h6M9 14h6M12 7v10"/></svg>),
  upload: (p) => (<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 4v12M7 9l5-5 5 5M5 20h14"/></svg>),
  settings: (p) => (<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="12" r="3"/><path d="M19 12a7 7 0 0 0-.1-1.2l2-1.6-2-3.4-2.3.9a7 7 0 0 0-2-1.2L14 3h-4l-.6 2.5a7 7 0 0 0-2 1.2l-2.3-.9-2 3.4 2 1.6A7 7 0 0 0 5 12c0 .4 0 .8.1 1.2l-2 1.6 2 3.4 2.3-.9a7 7 0 0 0 2 1.2L10 21h4l.6-2.5a7 7 0 0 0 2-1.2l2.3.9 2-3.4-2-1.6c.1-.4.1-.8.1-1.2z"/></svg>),
  search: (p) => (<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>),
  warn: (p) => (<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 3 2 20h20L12 3z"/><path d="M12 10v5M12 18v.5"/></svg>),
  chevron: (p) => (<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="m9 6 6 6-6 6"/></svg>),
  plus: (p) => (<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 5v14M5 12h14"/></svg>),
  download: (p) => (<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 4v12M7 11l5 5 5-5M5 20h14"/></svg>),
  back: (p) => (<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="m15 6-6 6 6 6"/></svg>),
  filter: (p) => (<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M3 5h18M6 12h12M10 19h4"/></svg>),
  bell: (p) => (<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M6 16V11a6 6 0 0 1 12 0v5l1.5 2h-15L6 16z"/><path d="M10 20a2 2 0 0 0 4 0"/></svg>),
};

function Button({ children, variant = "default", icon, onClick, disabled, style = {} }) {
  const variants = {
    default: { bg: "#fff", fg: "var(--ink-1)", bd: "var(--border)", hbg: "#F4F6FA" },
    primary: { bg: "var(--accent)", fg: "#fff", bd: "var(--accent)", hbg: "var(--accent-dark)" },
    danger: { bg: "#fff", fg: "var(--danger)", bd: "#F2BFBF", hbg: "#FCE4E4" },
    ghost: { bg: "transparent", fg: "var(--ink-2)", bd: "transparent", hbg: "#F0F3F8" },
  };
  const v = variants[variant];
  const [hover, setHover] = useState(false);
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{
        display: "inline-flex", alignItems: "center", gap: 6,
        height: 30, padding: "0 12px", fontSize: 12.5, fontWeight: 600,
        background: hover && !disabled ? v.hbg : v.bg, color: v.fg, border: `1px solid ${v.bd}`,
        borderRadius: 6, cursor: disabled ? "not-allowed" : "pointer",
        opacity: disabled ? 0.5 : 1, transition: "background .12s",
        fontFamily: "inherit",
        ...style,
      }}>
      {icon}{children}
    </button>
  );
}

function Select({ value, onChange, options, placeholder = "選択", style = {}, prefix }) {
  return (
    <label style={{ display: "inline-flex", alignItems: "center", gap: 6, position: "relative", ...style }}>
      {prefix && <span style={{ fontSize: 12, color: "var(--ink-3)", whiteSpace: "nowrap" }}>{prefix}</span>}
      <select
        value={value}
        onChange={e => onChange(e.target.value)}
        style={{
          height: 30, padding: "0 26px 0 10px", fontSize: 12.5,
          background: "#fff", border: "1px solid var(--border)", borderRadius: 6,
          color: "var(--ink-1)", appearance: "none", cursor: "pointer",
          backgroundImage: `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%23667' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><path d='m6 9 6 6 6-6'/></svg>")`,
          backgroundRepeat: "no-repeat", backgroundPosition: "right 8px center",
          fontFamily: "inherit",
        }}>
        {placeholder && <option value="">{placeholder}</option>}
        {options.map(o => (
          <option key={o.value} value={o.value}>{o.label}</option>
        ))}
      </select>
    </label>
  );
}

function SearchInput({ value, onChange, placeholder = "検索", style = {} }) {
  return (
    <div style={{ position: "relative", display: "inline-flex", ...style }}>
      <span style={{ position: "absolute", left: 9, top: "50%", transform: "translateY(-50%)", color: "var(--ink-3)", display: "flex" }}>
        <Icon.search />
      </span>
      <input
        value={value}
        onChange={e => onChange(e.target.value)}
        placeholder={placeholder}
        style={{
          height: 30, paddingLeft: 28, paddingRight: 10, fontSize: 12.5,
          background: "#fff", border: "1px solid var(--border)", borderRadius: 6,
          color: "var(--ink-1)", width: "100%", fontFamily: "inherit",
          outline: "none",
        }}
        onFocus={e => e.target.style.borderColor = "var(--accent)"}
        onBlur={e => e.target.style.borderColor = "var(--border)"}
      />
    </div>
  );
}

function Field({ label, value, mono }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 2, minWidth: 0 }}>
      <span style={{ fontSize: 11, color: "var(--ink-3)", fontWeight: 500 }}>{label}</span>
      <span style={{ fontSize: 13, color: "var(--ink-1)", fontFamily: mono ? "var(--font-num)" : "inherit", fontWeight: 500, overflow: "hidden", textOverflow: "ellipsis" }}>
        {value || <span style={{ color: "var(--ink-3)" }}>—</span>}
      </span>
    </div>
  );
}

const fmtJPY = (n) => "¥" + Number(n).toLocaleString("ja-JP");
const fmtN = (n) => Number(n).toLocaleString("ja-JP");

Object.assign(window, {
  Chip, StatusChip, KpiCard, SectionCard, BarChart, ColumnChart,
  DataTable, Icon, Button, Select, SearchInput, Field,
  fmtJPY, fmtN,
});
