// Chart components — SVG で描画 / カテゴリは濃淡 4 段階（ITコンサル/戦略系/総合系/SIer）
const { useState, useMemo, useRef, useEffect } = React;

// カテゴリ → CSS 変数へのマッピング
const CATEGORIES = ['ITコンサル', '戦略系', '総合系', 'SIer'];
const CAT_CLASS = { 'ITコンサル': 'consul', '戦略系': 'strategy', '総合系': 'sogo', 'SIer': 'sier' };

window.useTooltip = function () {
  const [tt, setTt] = useState(null);
  const show = (e, content) => setTt({ x: e.clientX + 12, y: e.clientY + 12, content });
  const hide = () => setTt(null);
  const TT = () => tt ? (<div className="tooltip" style={{ left: tt.x, top: tt.y }}>{tt.content}</div>) : null;
  return { show, hide, TT };
};

const catColor = (c) => ({
  'ITコンサル': 'var(--cat-consul-dot)',
  '戦略系':     'var(--cat-strategy-dot)',
  '総合系':     'var(--cat-sogo-dot)',
  'SIer':       'var(--cat-sier-dot)'
}[c] || 'var(--chart-secondary)');

const catBadgeClass = (c) => CAT_CLASS[c] || 'sier';

// ========== Ranking bars ==========
window.RankingChart = function ({ companies, highlightName, onSelect, selectedName }) {
  const max = Math.max(...companies.map(c => c.salary), 1);
  const { show, hide, TT } = window.useTooltip();
  return (
    <>
      <div className="ranking-list">
        {companies.map((c, i) => {
          const w = (c.salary / max) * 100;
          const isHL = highlightName === c.name;
          const isSel = selectedName === c.name;
          const dimmed = (highlightName || selectedName) && !isHL && !isSel;
          return (
            <div key={c.name}
              className={`rank-row ${c.estimated ? 'estimated' : ''} ${isHL ? 'highlighted' : ''} ${isSel ? 'selected' : ''} ${dimmed ? 'dimmed' : ''}`}
              onClick={() => onSelect && onSelect(c.name)}
              onMouseMove={e => show(e, <>
                <div className="tt-title">{c.name}</div>
                <div className="tt-row">平均年収 {c.salary.toLocaleString()} 万円</div>
                <div className="tt-row">平均年齢 {c.age} 歳 / 勤続 {c.tenure} 年</div>
                <div className="tt-row">従業員 {c.employees.toLocaleString()} 名</div>
              </>)}
              onMouseLeave={hide}>
              <div className="r-num">{i + 1}</div>
              <div className="r-name" title={c.name}>{c.short}</div>
              <div className="r-bar-wrap">
                <div className="r-bar" style={{ width: `${w}%` }} />
              </div>
              <div className="r-val">
                <span className="num">{c.salary.toLocaleString()}</span><span className="suf">万円</span>
              </div>
              <div className="r-cat-wrap">
                {c.estimated && <span className="est-mini">推定</span>}
                <span className={`cat-badge ${catBadgeClass(c.category)}`}>
                  {c.category}
                </span>
              </div>
            </div>
          );
        })}
      </div>
      <TT />
    </>
  );
};

// ========== Scatter ==========
window.ScatterChart = function ({ companies, xKey, yKey, xLabel, yLabel, xRange, yRange, highlightName, onSelect, selectedName, labelAll, showAvgLines, showQuadrants }) {
  const W = 560, H = 340;
  const PAD = { l: 48, r: 16, t: 20, b: 38 };
  const plotW = W - PAD.l - PAD.r, plotH = H - PAD.t - PAD.b;
  const [xMin, xMax] = xRange;
  const [yMin, yMax] = yRange;
  const sx = v => PAD.l + ((v - xMin) / (xMax - xMin)) * plotW;
  const sy = v => PAD.t + plotH - ((v - yMin) / (yMax - yMin)) * plotH;

  const xTicks = 5, yTicks = 5;
  const xStep = (xMax - xMin) / xTicks;
  const yStep = (yMax - yMin) / yTicks;

  const xAvg = companies.length ? companies.reduce((s, c) => s + c[xKey], 0) / companies.length : 0;
  const yAvg = companies.length ? companies.reduce((s, c) => s + c[yKey], 0) / companies.length : 0;

  const { show, hide, TT } = window.useTooltip();

  return (
    <>
      <svg className="chart-svg" viewBox={`0 0 ${W} ${H}`}>
        {Array.from({ length: yTicks + 1 }, (_, i) => {
          const v = yMin + i * yStep, y = sy(v);
          return (<g key={`y${i}`}>
            <line className="grid-line" x1={PAD.l} x2={W - PAD.r} y1={y} y2={y} />
            <text className="axis-label" x={PAD.l - 7} y={y + 3} textAnchor="end">{Math.round(v).toLocaleString()}</text>
          </g>);
        })}
        {Array.from({ length: xTicks + 1 }, (_, i) => {
          const v = xMin + i * xStep, x = sx(v);
          return (<g key={`x${i}`}>
            <line className="grid-line" x1={x} x2={x} y1={PAD.t} y2={H - PAD.b} />
            <text className="axis-label" x={x} y={H - PAD.b + 14} textAnchor="middle">{v.toFixed(0)}</text>
          </g>);
        })}
        <line className="axis-line" x1={PAD.l} x2={W - PAD.r} y1={H - PAD.b} y2={H - PAD.b} />
        <line className="axis-line" x1={PAD.l} x2={PAD.l} y1={PAD.t} y2={H - PAD.b} />
        <text className="axis-title" x={W - PAD.r} y={H - PAD.b + 30} textAnchor="end">{xLabel}</text>
        <text className="axis-title" x={PAD.l} y={PAD.t - 6} textAnchor="start">{yLabel}</text>

        {showAvgLines && companies.length > 0 && (
          <g>
            <line className="avg-line" x1={sx(xAvg)} x2={sx(xAvg)} y1={PAD.t} y2={H - PAD.b} />
            <line className="avg-line" x1={PAD.l} x2={W - PAD.r} y1={sy(yAvg)} y2={sy(yAvg)} />
            <text className="axis-label" x={sx(xAvg) + 3} y={PAD.t + 8}>平均 {xAvg.toFixed(1)}</text>
            <text className="axis-label" x={W - PAD.r - 3} y={sy(yAvg) - 3} textAnchor="end">平均 {Math.round(yAvg)}</text>
          </g>
        )}

        {showQuadrants && showAvgLines && (
          <g>
            <text className="quadrant-label" x={W - PAD.r - 4} y={PAD.t + 22} textAnchor="end">HIGH / HIGH</text>
            <text className="quadrant-label" x={PAD.l + 4} y={PAD.t + 22}>LOW / HIGH</text>
            <text className="quadrant-label" x={W - PAD.r - 4} y={H - PAD.b - 6} textAnchor="end">HIGH / LOW</text>
            <text className="quadrant-label" x={PAD.l + 4} y={H - PAD.b - 6}>LOW / LOW</text>
          </g>
        )}

        {companies.map(c => {
          const cx = sx(c[xKey]), cy = sy(c[yKey]);
          const isHL = highlightName === c.name;
          const isSel = selectedName === c.name;
          const dim = (highlightName || selectedName) && !isHL && !isSel;
          const r = isSel ? 7 : isHL ? 6 : 4.5;
          // 推定値は中空（surface 背景）＋オークル枠、実績はカテゴリ濃淡で塗り
          const baseColor = catColor(c.category);
          const fill = c.estimated ? 'var(--surface)' : baseColor;
          const strokeCol = c.estimated ? 'var(--src-estimate)' : baseColor;
          return (
            <g key={c.name}>
              {isSel && <circle cx={cx} cy={cy} r={12} fill="none" stroke={baseColor} strokeWidth={1} opacity={0.4} />}
              <circle className="dot" cx={cx} cy={cy} r={r}
                fill={fill} stroke={strokeCol} strokeWidth={isSel ? 3 : c.estimated ? 2 : 1.5}
                opacity={dim ? 0.25 : 1}
                onMouseMove={e => show(e, <>
                  <div className="tt-title">{c.short}</div>
                  <div className="tt-row">{xLabel}: {c[xKey]}</div>
                  <div className="tt-row">{yLabel}: {c[yKey].toLocaleString()}</div>
                </>)}
                onMouseLeave={hide}
                onClick={() => onSelect && onSelect(c.name)}
              />
              {(labelAll || isSel || isHL) && (
                <text className="dot-label" x={cx + (r + 3)} y={cy + 3} style={isSel ? { fontWeight: 700 } : {}}>{c.short}</text>
              )}
            </g>
          );
        })}
      </svg>
      <div className="legend-inline" style={{ marginTop: 8, paddingTop: 8, borderTop: '1px dotted var(--border-soft)' }}>
        <span><span className="sw sw-dot consul" /> ITコンサル</span>
        <span><span className="sw sw-dot strategy" /> 戦略系</span>
        <span><span className="sw sw-dot sogo" /> 総合系</span>
        <span><span className="sw sw-dot sier" /> SIer</span>
        <span><span className="sw-ring-est" /> 推定値（有報非開示）</span>
        {showAvgLines && <span><span className="sw-dash" /> 全体平均</span>}
      </div>
      <TT />
    </>
  );
};

// ========== Histogram (stacked by category) ==========
window.HistogramChart = function ({ companies, highlightName }) {
  const buckets = [600, 800, 1000, 1200, 1400, 1600, 1800, 2000, 2200];
  const rows = buckets.slice(0, -1).map((lo, i) => {
    const hi = buckets[i + 1];
    const inB = companies.filter(c => c.salary >= lo && c.salary < hi);
    const perCat = CATEGORIES.map(cat => ({
      cat,
      items: inB.filter(c => c.category === cat)
    })).filter(g => g.items.length > 0);
    return { lo, hi, perCat, total: inB.length, companies: inB };
  });
  const max = Math.max(...rows.map(r => r.total), 1);
  return (
    <div>
      <div className="hist-chart">
        {rows.map(r => {
          const hasHL = highlightName && r.companies.some(c => c.name === highlightName);
          return (
            <div key={r.lo} className="hist-row">
              <div className="hist-label">{r.lo}–{r.hi}</div>
              <div className="hist-bar-wrap">
                {r.perCat.map(g => {
                  const hl = hasHL && g.items.some(c => c.name === highlightName);
                  return (
                    <div key={g.cat}
                      className={`hist-seg ${catBadgeClass(g.cat)} ${hl ? 'hl' : ''}`}
                      style={{ width: `${(g.items.length / max) * 100}%` }}
                      title={`${g.cat} ${g.items.length}社`} />
                  );
                })}
              </div>
              <div className="hist-cnt">{r.total}<span className="suf">社</span></div>
            </div>
          );
        })}
      </div>
      <div className="legend-inline" style={{ marginTop: 8, paddingTop: 8, borderTop: '1px dotted var(--border-soft)' }}>
        <span><span className="sw consul" /> ITコンサル</span>
        <span><span className="sw strategy" /> 戦略系</span>
        <span><span className="sw sogo" /> 総合系</span>
        <span><span className="sw sier" /> SIer</span>
        <span style={{ marginLeft: 'auto', color: 'var(--text-muted)' }}>単位: 万円 / 横軸: 企業数</span>
      </div>
    </div>
  );
};

// ========== Category compare (box plot horizontal) ==========
window.CategoryCompare = function ({ companies }) {
  const stats = CATEGORIES.map(g => {
    const vals = companies.filter(c => c.category === g).map(c => c.salary).sort((a, b) => a - b);
    if (!vals.length) return { g, n: 0 };
    const med = vals[Math.floor(vals.length / 2)];
    const avg = Math.round(vals.reduce((s, v) => s + v, 0) / vals.length);
    const min = vals[0], max = vals[vals.length - 1];
    const q1 = vals[Math.floor(vals.length * 0.25)];
    const q3 = vals[Math.floor(vals.length * 0.75)];
    return { g, n: vals.length, min, max, med, avg, q1, q3, vals, companies: companies.filter(c => c.category === g) };
  });
  const validStats = stats.filter(s => s.n);
  if (!validStats.length) return <div className="detail-empty">対象データがありません</div>;
  const gMin = Math.min(...validStats.map(s => s.min)) - 50;
  const gMax = Math.max(...validStats.map(s => s.max)) + 50;
  const rowHeight = 56;
  const topPad = 18;
  const W = 560, H = topPad + validStats.length * rowHeight + 36;
  const PAD = { l: 100, r: 30, t: topPad, b: 36 };
  const plotW = W - PAD.l - PAD.r;
  const sx = v => PAD.l + ((v - gMin) / (gMax - gMin)) * plotW;

  return (
    <div>
      <svg className="chart-svg" viewBox={`0 0 ${W} ${H}`}>
        {[0, 0.25, 0.5, 0.75, 1].map((t, i) => {
          const v = gMin + (gMax - gMin) * t;
          return (<g key={i}>
            <line className="grid-line" x1={sx(v)} x2={sx(v)} y1={PAD.t - 6} y2={H - PAD.b} />
            <text className="axis-label" x={sx(v)} y={H - PAD.b + 14} textAnchor="middle">{Math.round(v)}</text>
          </g>);
        })}
        <line className="axis-line" x1={PAD.l} x2={W - PAD.r} y1={H - PAD.b} y2={H - PAD.b} />
        <text className="axis-title" x={W - PAD.r} y={H - PAD.b + 30} textAnchor="end">平均年収（万円）</text>

        {validStats.map((s, i) => {
          const y = PAD.t + 18 + i * rowHeight;
          const color = catColor(s.g);
          return (
            <g key={s.g}>
              <text className="axis-title" x={PAD.l - 12} y={y + 4} textAnchor="end" style={{ fontWeight: 700 }}>{s.g}</text>
              <text className="axis-label" x={PAD.l - 12} y={y + 18} textAnchor="end">n = {s.n}</text>

              <line x1={sx(s.min)} x2={sx(s.max)} y1={y} y2={y} stroke="var(--chart-neutral)" strokeWidth={1.5} />
              <line x1={sx(s.min)} x2={sx(s.min)} y1={y - 7} y2={y + 7} stroke="var(--chart-neutral)" strokeWidth={1.5} />
              <line x1={sx(s.max)} x2={sx(s.max)} y1={y - 7} y2={y + 7} stroke="var(--chart-neutral)" strokeWidth={1.5} />

              <rect x={sx(s.q1)} y={y - 10} width={Math.max(sx(s.q3) - sx(s.q1), 1)} height={20} fill={color} opacity={0.18} stroke={color} strokeOpacity={0.5} />
              <line x1={sx(s.med)} x2={sx(s.med)} y1={y - 11} y2={y + 11} stroke={color} strokeWidth={3} />

              {s.companies.map((c) => (
                <circle key={c.name} cx={sx(c.salary)} cy={y} r={2.5} fill={color} opacity={0.65} />
              ))}

              <g transform={`translate(${sx(s.avg)}, ${y})`}>
                <line y1={-11} y2={11} stroke="var(--surface)" strokeWidth={3} />
                <path d="M -5 -11 L 5 -11 L 0 -6 Z" fill="var(--text)" />
                <path d="M -5 11 L 5 11 L 0 6 Z" fill="var(--text)" />
              </g>

              <text className="dot-label" x={sx(s.med)} y={y - 15} textAnchor="middle" style={{ fontWeight: 700, fill: color }}>中央値 {s.med}</text>
              <text className="dot-label" x={sx(s.avg)} y={y + 24} textAnchor="middle" style={{ fontWeight: 700 }}>平均 {s.avg}</text>
            </g>
          );
        })}
      </svg>
      <div className="legend-inline" style={{ marginTop: 6, paddingTop: 8, borderTop: '1px dotted var(--border-soft)' }}>
        <span><span className="sw secondary" style={{ opacity: 0.3 }} /> Q1–Q3（四分位範囲）</span>
        <span><span style={{ display: 'inline-block', width: 2, height: 10, background: 'var(--text)', marginRight: 5, verticalAlign: 'middle' }} /> 中央値</span>
        <span><span style={{ display: 'inline-block', width: 8, height: 8, background: 'var(--text)', clipPath: 'polygon(50% 0, 100% 100%, 0 100%)', marginRight: 5, verticalAlign: 'middle' }} /> 平均値</span>
        <span><span className="sw neutral" /> Min–Max</span>
      </div>
    </div>
  );
};

// ========== Time series ==========
window.TimeSeriesChart = function ({ data }) {
  const W = 560, H = 280;
  const PAD = { l: 48, r: 84, t: 20, b: 36 };
  const plotW = W - PAD.l - PAD.r, plotH = H - PAD.t - PAD.b;
  const years = data.years;
  const allVals = Object.values(data.categories).flat();
  const yMin = Math.floor(Math.min(...allVals) / 100) * 100 - 50;
  const yMax = Math.ceil(Math.max(...allVals) / 100) * 100 + 50;
  const sx = i => PAD.l + (i / (years.length - 1)) * plotW;
  const sy = v => PAD.t + plotH - ((v - yMin) / (yMax - yMin)) * plotH;
  const yTicks = 4;
  const yStep = (yMax - yMin) / yTicks;
  const cats = Object.keys(data.categories);
  const colorFor = (c) => catColor(c);

  const { show, hide, TT } = window.useTooltip();

  // ラベルが重ならないよう最終値で y 位置をオフセット
  const labelYs = cats.map(c => {
    const vals = data.categories[c];
    return { cat: c, y: sy(vals[vals.length - 1]), v: vals[vals.length - 1] };
  }).sort((a, b) => a.y - b.y);
  const adjusted = {};
  const MIN_GAP = 14;
  for (let i = 0; i < labelYs.length; i++) {
    const cur = labelYs[i];
    if (i === 0) { adjusted[cur.cat] = cur.y; continue; }
    const prev = adjusted[labelYs[i - 1].cat];
    adjusted[cur.cat] = Math.max(cur.y, prev + MIN_GAP);
  }

  return (
    <>
      <svg className="chart-svg" viewBox={`0 0 ${W} ${H}`}>
        {Array.from({ length: yTicks + 1 }, (_, i) => {
          const v = yMin + i * yStep, y = sy(v);
          return (<g key={i}>
            <line className="grid-line" x1={PAD.l} x2={W - PAD.r} y1={y} y2={y} />
            <text className="axis-label" x={PAD.l - 7} y={y + 3} textAnchor="end">{Math.round(v)}</text>
          </g>);
        })}
        <line className="axis-line" x1={PAD.l} x2={W - PAD.r} y1={H - PAD.b} y2={H - PAD.b} />
        <line className="axis-line" x1={PAD.l} x2={PAD.l} y1={PAD.t} y2={H - PAD.b} />
        {years.map((yr, i) => (
          <text key={yr} className="axis-label" x={sx(i)} y={H - PAD.b + 14} textAnchor="middle">{yr}</text>
        ))}
        <text className="axis-title" x={PAD.l} y={PAD.t - 6} textAnchor="start">平均年収（万円）</text>

        {cats.map(c => {
          const vals = data.categories[c];
          const color = colorFor(c);
          const areaD = [
            `M ${sx(0)} ${sy(yMin)}`,
            ...vals.map((v, i) => `L ${sx(i)} ${sy(v)}`),
            `L ${sx(vals.length - 1)} ${sy(yMin)} Z`
          ].join(' ');
          const d = vals.map((v, i) => `${i === 0 ? 'M' : 'L'} ${sx(i)} ${sy(v)}`).join(' ');
          const labelY = adjusted[c];
          return (
            <g key={c}>
              <path d={areaD} fill={color} opacity={0.06} />
              <path d={d} fill="none" stroke={color} strokeWidth={2.25} strokeLinecap="round" strokeLinejoin="round" />
              {vals.map((v, i) => (
                <g key={i}>
                  <circle cx={sx(i)} cy={sy(v)} r={6} fill="transparent"
                    onMouseMove={e => show(e, <>
                      <div className="tt-title">{c} / {years[i]}</div>
                      <div className="tt-row">平均年収 {v} 万円</div>
                      {i > 0 && <div className="tt-row">前年比 {v - vals[i-1] >= 0 ? '+' : ''}{v - vals[i-1]} 万円</div>}
                    </>)}
                    onMouseLeave={hide} />
                  <circle cx={sx(i)} cy={sy(v)} r={3.5} fill="var(--surface)" stroke={color} strokeWidth={2} pointerEvents="none" />
                </g>
              ))}
              <text x={sx(vals.length - 1) + 8} y={labelY + 4} className="dot-label" style={{ fontWeight: 700, fill: color }}>{c}</text>
              <text x={sx(vals.length - 1) + 8} y={labelY + 16} className="axis-label" style={{ fill: color, opacity: 0.7 }}>{vals[vals.length - 1]}</text>
            </g>
          );
        })}
      </svg>
      <TT />
    </>
  );
};

// ========== Sparkline ==========
window.Spark = function ({ values, width = 72, height = 22, color = 'var(--text)' }) {
  const min = Math.min(...values), max = Math.max(...values);
  const sx = i => (i / (values.length - 1)) * (width - 4) + 2;
  const sy = v => height - 3 - ((v - min) / (max - min || 1)) * (height - 6);
  const d = values.map((v, i) => `${i === 0 ? 'M' : 'L'} ${sx(i)} ${sy(v)}`).join(' ');
  const areaD = d + ` L ${sx(values.length - 1)} ${height} L ${sx(0)} ${height} Z`;
  return (
    <svg className="sparkline" width={width} height={height}>
      <path d={areaD} fill={color} opacity={0.12} />
      <path d={d} fill="none" stroke={color} strokeWidth={1.4} strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={sx(values.length - 1)} cy={sy(values[values.length - 1])} r={2} fill={color} />
    </svg>
  );
};
