// components/RankShift.jsx — Self-ranked competence, re-sequencing across years.
// Styled as a liner-notes "rotation" rather than a data chart: four snapshot
// labels, five chart positions, the expertise areas threaded as tape ribbons
// that climb and drop between them. Data is Merijn's own self-ranking,
// transcribed verbatim — no invented numbers.
//
//   Sequence:  Year 1 → Year 2 → B3.1 → B3.2 (now)
//   Position 1 = top of the rotation.

const RS_STAGES = [
  { id: 'y1',  main: 'Year 1', tag: '01', sub: 'yr 1' },
  { id: 'y2',  main: 'Year 2', tag: '02', sub: 'yr 2' },
  { id: 'b31', main: 'B3.1',   tag: '03', sub: 'yr 3 · s1' },
  { id: 'now', main: 'B3.2',   tag: '04', sub: 'now' },
];

// ranks[] read in the same order as RS_STAGES.
const RS_AREAS = [
  { id: 'tr', abbr: 'T&R', name: 'Technology & Realization',     color: '#F2876B', tint: '#FBD6C9', ink: '#C24E33', ranks: [1, 1, 1, 2] },
  { id: 'mc', abbr: 'MDC', name: 'Math, Data & Computing',       color: '#7FB5E8', tint: '#CFE5F7', ink: '#2F6FAE', ranks: [3, 2, 2, 1] },
  { id: 'us', abbr: 'U&S', name: 'User & Society',               color: '#B9A3E3', tint: '#E2D8F4', ink: '#6E54A8', ranks: [4, 5, 3, 3] },
  { id: 'be', abbr: 'B&E', name: 'Business & Entrepreneurship',  color: '#F2D98A', tint: '#F8ECC4', ink: '#A37E22', ranks: [5, 4, 4, 4] },
  { id: 'ca', abbr: 'C&A', name: 'Creativity & Aesthetics',      color: '#93CE8F', tint: '#CDE9CB', ink: '#3B7A3E', ranks: [2, 3, 5, 5] },
];

// ── geometry (SVG user units; scales with viewBox) ──
const RS_W = 1060, RS_H = 470;
const RS_PAD = { l: 152, r: 250, t: 96, b: 40 };
const rsX = (i) => RS_PAD.l + i * ((RS_W - RS_PAD.r - RS_PAD.l) / (RS_STAGES.length - 1));
const rsY = (rank) => RS_PAD.t + (rank - 1) * ((RS_H - RS_PAD.b - RS_PAD.t) / (RS_AREAS.length - 1));

// Smooth S-curve path between rank nodes (horizontal control handles).
function rsPath(ranks) {
  const pts = ranks.map((r, i) => [rsX(i), rsY(r)]);
  let d = `M ${pts[0][0]} ${pts[0][1]}`;
  for (let i = 1; i < pts.length; i++) {
    const [x0, y0] = pts[i - 1];
    const [x1, y1] = pts[i];
    const mx = (x0 + x1) / 2;
    d += ` C ${mx} ${y0} ${mx} ${y1} ${x1} ${y1}`;
  }
  return d;
}

function RankShift() {
  const [hover, setHover]   = React.useState(null);
  const [pinned, setPinned] = React.useState(null);
  const [stage, setStage]   = React.useState(RS_STAGES.length - 1);
  const refs = React.useRef({});

  const focus = hover || pinned;
  const dim = (id) => focus && focus !== id;

  // Draw-on animation: thread the ribbons in on mount, staggered.
  React.useEffect(() => {
    const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    RS_AREAS.forEach((a, i) => {
      const pair = refs.current[a.id];
      if (!pair) return;
      [pair.tint, pair.ink].forEach((el) => {
        if (!el) return;
        const len = el.getTotalLength();
        el.style.transition = 'none';
        el.style.strokeDasharray = len;
        el.style.strokeDashoffset = reduce ? 0 : len;
        if (reduce) return;
        el.getBoundingClientRect();
        el.style.transition = `stroke-dashoffset 1000ms cubic-bezier(0.25,0,0,1) ${140 + i * 95}ms`;
        el.style.strokeDashoffset = 0;
      });
    });
  }, []);

  return (
    <div style={{ background: '#FFFFFF', border: '1px solid var(--c-border)' }}>

      {/* catalog strip — print/liner-notes header, not a chart legend */}
      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between',
                    gap: 16, padding: '16px 24px 12px', borderBottom: '2px solid var(--c-smoke)' }}>
        <div style={{ fontFamily: 'var(--font-display)', fontSize: 17, fontWeight: 700,
                      letterSpacing: '-0.01em', color: 'var(--c-smoke)' }}>
          Rotation<span style={{ color: 'var(--ink-coral)' }}> · </span>what leads my practice
        </div>
        <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.12em',
                      textTransform: 'uppercase', color: 'var(--c-muted)' }}>
          5 positions · 4 snapshots
        </div>
      </div>

      {/* ── the rotation ── */}
      <div style={{ padding: '6px 22px 8px' }}>
        <svg viewBox={`0 0 ${RS_W} ${RS_H}`} width="100%" style={{ display: 'block', overflow: 'visible' }} role="img"
          aria-label="Self-ranked expertise areas re-sequencing across four yearly snapshots">

          {/* position lanes: big watermark numeral + dotted registration rule */}
          {RS_AREAS.map((_, r) => {
            const y = rsY(r + 1);
            const top = r === 0;
            return (
              <g key={'lane' + r}>
                <line x1={RS_PAD.l - 36} y1={y} x2={RS_W - RS_PAD.r + 8} y2={y}
                  stroke={top ? '#D7B3A6' : '#DCE1E6'} strokeWidth="1" strokeDasharray="1 7" strokeLinecap="round" />
                <text x={74} y={y + 13} textAnchor="middle"
                  style={{ fontFamily: 'var(--font-display)', fontSize: 38, fontWeight: 700,
                           letterSpacing: '-0.03em', fill: top ? '#F0C9BC' : '#E4E9ED' }}>
                  {r + 1}
                </text>
                {top && (
                  <text x={74} y={y - 22} textAnchor="middle"
                    style={{ fontFamily: 'var(--font-mono)', fontSize: 9, fontWeight: 600,
                             letterSpacing: '0.18em', fill: 'var(--ink-coral)' }}>
                    LEAD
                  </text>
                )}
              </g>
            );
          })}

          {/* focused-column registration marks */}
          <g style={{ transition: 'transform 280ms cubic-bezier(0.25,0,0,1)', transform: `translateX(${rsX(stage) - rsX(0)}px)` }}>
            <line x1={rsX(0)} y1={RS_PAD.t - 14} x2={rsX(0)} y2={RS_H - RS_PAD.b + 14}
              stroke="var(--c-smoke)" strokeWidth="1" strokeDasharray="2 6" opacity="0.45" />
          </g>

          {/* snapshot label cards */}
          {RS_STAGES.map((s, i) => {
            const now = i === RS_STAGES.length - 1;
            const on = i === stage;
            const cx = rsX(i);
            const fill = now ? 'var(--c-smoke)' : (on ? '#F6F8FA' : '#FFFFFF');
            const mainFill = now ? '#FFFFFF' : 'var(--c-smoke)';
            const subFill = now ? '#C7CDD3' : 'var(--c-muted)';
            const tagFill = now ? 'var(--p-coral)' : (on ? 'var(--ink-coral)' : '#B7BFC6');
            return (
              <g key={s.id} style={{ cursor: 'pointer' }} onClick={() => setStage(i)}>
                <rect x={cx - 64} y={6} width={128} height={62} fill={fill}
                  stroke={now ? 'var(--c-smoke)' : (on ? 'var(--c-smoke)' : 'var(--c-border)')}
                  strokeWidth={on && !now ? 1.6 : 1} />
                <text x={cx - 52} y={26} style={{ fontFamily: 'var(--font-mono)', fontSize: 11, fontWeight: 600,
                  letterSpacing: '0.1em', fill: tagFill }}>{s.tag}</text>
                <text x={cx} y={44} textAnchor="middle" style={{ fontFamily: 'var(--font-display)', fontSize: 21,
                  fontWeight: 700, letterSpacing: '-0.02em', fill: mainFill }}>{s.main}</text>
                <text x={cx} y={60} textAnchor="middle" style={{ fontFamily: 'var(--font-mono)', fontSize: 9.5,
                  fontWeight: 600, letterSpacing: '0.14em', textTransform: 'uppercase', fill: subFill }}>{s.sub}</text>
              </g>
            );
          })}

          {/* ribbons — pastel tape with an ink centreline */}
          {RS_AREAS.map((a) => {
            const faded = dim(a.id);
            const d = rsPath(a.ranks);
            return (
              <g key={'r' + a.id} style={{ opacity: faded ? 0.1 : 1, transition: 'opacity 200ms', cursor: 'pointer' }}
                onMouseEnter={() => setHover(a.id)} onMouseLeave={() => setHover(null)}
                onClick={() => setPinned(pinned === a.id ? null : a.id)}>
                <path ref={(el) => { (refs.current[a.id] = refs.current[a.id] || {}).tint = el; }}
                  d={d} fill="none" stroke={a.color} strokeWidth={focus === a.id ? 11 : 8.5}
                  strokeLinecap="round" style={{ transition: 'stroke-width 200ms' }} />
                <path ref={(el) => { (refs.current[a.id] = refs.current[a.id] || {}).ink = el; }}
                  d={d} fill="none" stroke={a.ink} strokeWidth="2" strokeLinecap="round" opacity="0.85" />
              </g>
            );
          })}

          {/* nodes + right-edge tracklist labels */}
          {RS_AREAS.map((a) => {
            const faded = dim(a.id);
            const lastRank = a.ranks[a.ranks.length - 1];
            return (
              <g key={'n' + a.id} style={{ opacity: faded ? 0.12 : 1, transition: 'opacity 200ms' }}>
                {a.ranks.map((r, i) => {
                  const big = i === stage;
                  return (
                    <g key={i} style={{ cursor: 'pointer' }}
                      onMouseEnter={() => setHover(a.id)} onMouseLeave={() => setHover(null)}
                      onClick={() => setPinned(pinned === a.id ? null : a.id)}>
                      <circle cx={rsX(i)} cy={rsY(r)} r={big ? 16 : 13} fill={a.ink}
                        stroke="#FFFFFF" strokeWidth="2.5"
                        style={{ transition: 'r 220ms cubic-bezier(0.25,0,0,1)' }} />
                      <text x={rsX(i)} y={rsY(r) + 4} textAnchor="middle"
                        style={{ fontFamily: 'var(--font-display)', fontSize: big ? 11.5 : 10.5, fontWeight: 700,
                                 fill: '#FFFFFF', pointerEvents: 'none', letterSpacing: '-0.01em' }}>
                        {a.abbr}
                      </text>
                    </g>
                  );
                })}
                {/* right edge — current standing, like the final tracklist */}
                <text x={RS_W - RS_PAD.r + 24} y={rsY(lastRank) - 2}
                  style={{ fontFamily: 'var(--font-mono)', fontSize: 10, fontWeight: 600, letterSpacing: '0.1em',
                           fill: 'var(--c-muted)' }}>
                  {'#' + lastRank}
                </text>
                <text x={RS_W - RS_PAD.r + 24} y={rsY(lastRank) + 13}
                  style={{ fontFamily: 'var(--font-body)', fontSize: 14.5, fontWeight: 700, fill: a.ink }}>
                  {a.name}
                </text>
              </g>
            );
          })}
        </svg>
      </div>

      {/* ── focused-snapshot tracklist + stepper ── */}
      <RankReadout stage={stage} setStage={setStage} focus={focus} setPinned={setPinned} pinned={pinned} setHover={setHover} />
    </div>
  );
}

/* ───────────────────────────────────────────────────────────────────────── */

function RankReadout({ stage, setStage, focus, pinned, setPinned, setHover }) {
  const ordered = [...RS_AREAS].sort((a, b) => a.ranks[stage] - b.ranks[stage]);
  const prev = stage > 0 ? stage - 1 : null;

  const delta = (a) => {
    if (prev == null) return { txt: 'baseline', dir: 0 };
    const d = a.ranks[prev] - a.ranks[stage];
    if (d === 0) return { txt: 'held', dir: 0 };
    return { txt: (d > 0 ? '▲ up ' : '▼ down ') + Math.abs(d), dir: Math.sign(d) };
  };

  const s = RS_STAGES[stage];

  return (
    <div style={{ borderTop: '1px solid var(--c-border)', background: '#FCFDFE' }}>
      {/* stepper */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                    padding: '12px 24px', borderBottom: '1px solid var(--c-border)' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
          <StepBtn label="‹" disabled={stage === 0} onClick={() => setStage(Math.max(0, stage - 1))} />
          <div style={{ minWidth: 176 }}>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
              <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, fontWeight: 600, color: 'var(--c-muted)' }}>{s.tag}</span>
              <span style={{ fontFamily: 'var(--font-display)', fontSize: 17, fontWeight: 700,
                             letterSpacing: '-0.015em', color: 'var(--c-smoke)' }}>{s.main}</span>
            </div>
            <div style={{ fontFamily: 'var(--font-body)', fontSize: 11, fontWeight: 600,
                          letterSpacing: '0.12em', textTransform: 'uppercase', color: 'var(--c-muted)' }}>
              Snapshot {stage + 1} of {RS_STAGES.length} · {s.sub}
            </div>
          </div>
          <StepBtn label="›" disabled={stage === RS_STAGES.length - 1} onClick={() => setStage(Math.min(RS_STAGES.length - 1, stage + 1))} />
        </div>
        <div style={{ display: 'flex', gap: 6 }}>
          {RS_STAGES.map((st, i) => (
            <button key={st.id} type="button" onClick={() => setStage(i)} title={st.main}
              style={{ appearance: 'none', border: 0, padding: 0, cursor: 'pointer',
                       width: i === stage ? 28 : 9, height: 9, background: i === stage ? 'var(--c-smoke)' : '#D6DCE2',
                       transition: 'width 240ms cubic-bezier(0.25,0,0,1), background 200ms' }} />
          ))}
        </div>
      </div>

      {/* the snapshot's tracklist, #1–#5 */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: 0 }}>
        {ordered.map((a, idx) => {
          const dl = delta(a);
          const dColor = dl.dir > 0 ? 'var(--ink-sage)' : dl.dir < 0 ? 'var(--ink-coral)' : 'var(--c-muted)';
          const off = focus && focus !== a.id;
          return (
            <div key={a.id}
              onMouseEnter={() => setHover(a.id)} onMouseLeave={() => setHover(null)}
              onClick={() => setPinned(pinned === a.id ? null : a.id)}
              style={{ padding: '16px 16px 18px', cursor: 'pointer',
                       borderLeft: idx === 0 ? 'none' : '1px solid var(--c-border)',
                       background: focus === a.id ? '#F4F7F9' : 'transparent',
                       opacity: off ? 0.38 : 1, transition: 'opacity 200ms, background 200ms' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 9, marginBottom: 10 }}>
                <span style={{ fontFamily: 'var(--font-display)', fontSize: 24, fontWeight: 700,
                               letterSpacing: '-0.03em', color: idx === 0 ? a.ink : 'var(--c-smoke)', lineHeight: 1 }}>
                  {idx + 1}
                </span>
                <span style={{ minWidth: 30, height: 22, padding: '0 7px', background: a.ink, display: 'inline-flex',
                               alignItems: 'center', justifyContent: 'center',
                               fontFamily: 'var(--font-display)', fontSize: 10.5, fontWeight: 700, color: '#fff' }}>
                  {a.abbr}
                </span>
              </div>
              <div style={{ fontFamily: 'var(--font-body)', fontSize: 13, fontWeight: 600, lineHeight: 1.3,
                            color: 'var(--c-smoke)', marginBottom: 8, minHeight: 34 }}>
                {a.name}
              </div>
              <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, fontWeight: 600,
                            letterSpacing: '0.04em', textTransform: 'uppercase', color: dColor }}>
                {dl.txt}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function StepBtn({ label, onClick, disabled }) {
  return (
    <button type="button" onClick={onClick} disabled={disabled}
      style={{ appearance: 'none', width: 34, height: 34, border: '1px solid var(--c-border)',
               background: disabled ? '#F2F5F8' : '#FFFFFF', color: disabled ? '#C4CBD2' : 'var(--c-smoke)',
               fontFamily: 'var(--font-display)', fontSize: 20, lineHeight: 1, fontWeight: 700,
               cursor: disabled ? 'default' : 'pointer', flexShrink: 0 }}>
      {label}
    </button>
  );
}

window.RankShift = RankShift;
