// Planning visual — Worker↔Truck assignment optimization.
// On scroll-in: a messy initial assignment (conflicts, mismatches) rearranges
// itself into the optimal solution (every operator skill-matched to a route).
// Companion to Hero Act 4 — same problem, deeper presentation with hard stats.

// 6 operators × 6 routes. Each operator has a skill set, each route requires skills.
// Initial assignment has skill mismatches (red lines); optimal assignment is all green.
const PV_OPERATORS = [
  { id: 'OP-01', skills: ['HGV-C', 'Hazmat']     },
  { id: 'OP-02', skills: ['HGV-C', 'Refrig.']    },
  { id: 'OP-03', skills: ['HGV-CE', 'Hazmat']    },
  { id: 'OP-04', skills: ['HGV-C']               },
  { id: 'OP-05', skills: ['HGV-CE', 'Refrig.']   },
  { id: 'OP-06', skills: ['HGV-C', 'ADR']        },
];
const PV_ROUTES = [
  { id: 'R-01', need: 'Hazmat',  hours: 7.5 },
  { id: 'R-02', need: 'Refrig.', hours: 8.5 },
  { id: 'R-03', need: 'HGV-CE',  hours: 9.2 },
  { id: 'R-04', need: 'HGV-C',   hours: 6.8 },
  { id: 'R-05', need: 'ADR',     hours: 7.8 },
  { id: 'R-06', need: 'Refrig.', hours: 8.1 },
];
// Initial (sub-optimal) assignment — operator index → route index
const PV_INITIAL = [3, 5, 4, 0, 1, 2];
// Optimal assignment — every operator matches their route's skill need
const PV_OPTIMAL = [0, 1, 2, 3, 4, 5];

function _pvSkillMatch(op, route) {
  return op.skills.includes(route.need);
}

function PlanningVisual() {
  const ref = React.useRef(null);
  const [run, setRun] = React.useState(false);
  const [phase, setPhase] = React.useState(0);  // 0 = initial, 1 = exploring, 2 = solved

  React.useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(
      (entries) => entries.forEach((e) => { if (e.isIntersecting && !run) setRun(true); }),
      { threshold: 0.3 }
    );
    io.observe(ref.current);
    return () => io.disconnect();
  }, [run]);

  React.useEffect(() => {
    if (!run) return;
    const t1 = setTimeout(() => setPhase(1), 600);
    const t2 = setTimeout(() => setPhase(2), 1900);
    return () => { clearTimeout(t1); clearTimeout(t2); };
  }, [run]);

  // SVG layout
  const W = 720, H = 360;
  const opX = 70, trX = W - 90;
  const opSpacing = (H - 60) / (PV_OPERATORS.length - 1);
  const opY = (i) => 30 + i * opSpacing;
  const trY = (i) => 30 + i * opSpacing;

  // Current assignment based on phase
  const currentAssign = phase < 2 ? PV_INITIAL : PV_OPTIMAL;

  // Flicker target while "exploring"
  const [flicker, setFlicker] = React.useState(0);
  React.useEffect(() => {
    if (phase !== 1) return;
    const iv = setInterval(() => setFlicker((f) => (f + 1) % 9), 120);
    return () => clearInterval(iv);
  }, [phase]);

  // Stats
  const conflicts = phase < 2
    ? PV_INITIAL.filter((rIdx, oIdx) => !_pvSkillMatch(PV_OPERATORS[oIdx], PV_ROUTES[rIdx])).length
    : 0;
  const coverage = phase < 2 ? 67 : 100;
  const idle = phase < 2 ? '2.4 h' : '0.3 h';
  const cost = phase < 2 ? '€ 4,820' : '€ 3,940';

  return (
    <div className="planning-vis" ref={ref}>
      <div className="vis-tag">
        <i></i>Schedule rebuild · {run ? (phase === 2 ? 'optimized' : 'solving') : 'pending'}
      </div>

      <div className="pv-bipartite">
        <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet">
          {/* All candidate edges (faint) */}
          <g stroke="currentColor" strokeWidth="0.4" strokeDasharray="3 3" opacity="0.18">
            {PV_OPERATORS.flatMap((_, oi) =>
              PV_ROUTES.map((_, ti) => (
                <line key={`c-${oi}-${ti}`}
                  x1={opX + 14} y1={opY(oi)} x2={trX - 18} y2={trY(ti)}/>
              ))
            )}
          </g>

          {/* Active assignment lines (current state) */}
          <g>
            {PV_OPERATORS.map((op, oi) => {
              const ti = currentAssign[oi];
              const match = _pvSkillMatch(op, PV_ROUTES[ti]);
              const color = match ? 'var(--accent)' : '#e25b5b';
              const isFlicker = phase === 1 && oi === flicker % PV_OPERATORS.length;
              return (
                <line key={`a-${oi}`}
                  x1={opX + 14} y1={opY(oi)} x2={trX - 18} y2={trY(ti)}
                  stroke={color}
                  strokeWidth={isFlicker ? 2.6 : (match ? 2 : 1.4)}
                  opacity={isFlicker ? 1 : (match ? 0.95 : 0.7)}
                  style={{
                    transition: 'all .6s cubic-bezier(.4,.7,.3,1)',
                    filter: match ? 'drop-shadow(0 0 3px color-mix(in oklab, var(--accent) 50%, transparent))' : 'none',
                  }}
                />
              );
            })}
          </g>

          {/* Operator nodes */}
          {PV_OPERATORS.map((op, oi) => (
            <g key={op.id} transform={`translate(${opX}, ${opY(oi)})`}>
              <circle r="14" fill="var(--bg-2)" stroke="var(--line)" strokeWidth="1"/>
              {/* worker silhouette */}
              <circle cx="0" cy="-3" r="3.6" fill="var(--fg-2)"/>
              <path d="M -6.5,5 Q -6.5,-1 0,-1 Q 6.5,-1 6.5,5 Z" fill="var(--fg-2)"/>
              <text x="-22" y="3" fontFamily="var(--mono)" fontSize="9"
                fill="var(--fg-3)" textAnchor="end" letterSpacing="0.5">
                {op.id}
              </text>
              <text x="-22" y="13" fontFamily="var(--mono)" fontSize="7"
                fill="var(--fg-3)" textAnchor="end" letterSpacing="0.3" opacity="0.6">
                {op.skills.join(' · ')}
              </text>
            </g>
          ))}

          {/* Route nodes */}
          {PV_ROUTES.map((r, ti) => (
            <g key={r.id} transform={`translate(${trX}, ${trY(ti)})`}>
              <rect x="-14" y="-8" width="28" height="16" rx="3"
                fill="var(--bg-2)" stroke="var(--accent)" strokeWidth="0.9" opacity="0.9"/>
              <rect x="-11" y="-5" width="10" height="11" fill="var(--accent)" opacity="0.7"/>
              <text x="22" y="-1" fontFamily="var(--mono)" fontSize="9"
                fill="var(--fg-3)" letterSpacing="0.5">
                {r.id}
              </text>
              <text x="22" y="10" fontFamily="var(--mono)" fontSize="7"
                fill="var(--fg-3)" letterSpacing="0.3" opacity="0.6">
                {r.need} · {r.hours}h
              </text>
            </g>
          ))}
        </svg>
      </div>

      <div className="pv-stats">
        <div className="pv-stat">
          <span className="pv-stat-l">Skill conflicts</span>
          <strong className={phase === 2 ? 'pv-good' : 'pv-bad'}>{conflicts}</strong>
        </div>
        <div className="pv-stat">
          <span className="pv-stat-l">Coverage</span>
          <strong className={phase === 2 ? 'pv-good' : ''}>{coverage}%</strong>
        </div>
        <div className="pv-stat">
          <span className="pv-stat-l">Avg idle</span>
          <strong className={phase === 2 ? 'pv-good' : ''}>{idle}</strong>
        </div>
        <div className="pv-stat">
          <span className="pv-stat-l">Daily cost</span>
          <strong className={phase === 2 ? 'pv-good' : ''}>{cost}</strong>
        </div>
      </div>
    </div>
  );
}

window.PlanningVisual = PlanningVisual;
