// HeroOrchestratorView.jsx
//
// Minimal hero illustration with a *discrete* output pipeline.
// Multiple kinds of map information stream into the Orchestrator hub;
// every ~3.5s a batch is "mixed", the hub pulses while it works, and
// a new Plan pill pops into the leftmost belt slot. Existing plans
// slide one slot right; the oldest falls off the end.
//
// Pure SVG hairlines + dots + pills — no content cards. Animation is
// state-driven (React) so each plan emergence is a clear discrete
// event rather than a continuous slide.

const HOV_INPUTS = [
  // Labels and kinds mirror the actual systems Orchestrator coordinates,
  // per the product description: ERP, PLM, MES, QMS, Excel, email,
  // databases, and approval workflows.
  { id: "email",     label: "EMAIL",     x:  88, y:  70, kind: "envelope" },
  { id: "excel",     label: "EXCEL",     x: 248, y:  90, kind: "grid"     },
  { id: "erp",       label: "ERP",       x: 138, y: 180, kind: "card"     },
  { id: "plm",       label: "PLM",       x: 308, y: 200, kind: "lines"    },
  { id: "mes",       label: "MES",       x:  88, y: 280, kind: "ping"     },
  { id: "qms",       label: "QMS",       x: 268, y: 300, kind: "check"    },
  { id: "db",        label: "DB",        x: 158, y: 380, kind: "stack"    },
  { id: "approvals", label: "APPROVALS", x: 328, y: 380, kind: "cal"      },
];

const PLAN_POOL = [
  "MTHEND-RECON",
  "VENDOR-ONBOARD",
  "SPEC-CHANGE",
  "BATCH-RELEASE",
  "SHIFT-HANDOVER",
  "STAND-UP-RECAP",
  "PPAP-REVIEW",
  "COMMS-WRAP",
];

// Geometry — viewBox 1280 × 460
// Composition reads left → right: inputs (28%) → hub (centered ~50%)
// → plan belt (right half). Hub is intentionally a bit bigger to act
// as the focal anchor that the headline above sits over.
const HUB        = { x: 640, y: 230, rOuter: 102, rMid: 72, rInner: 38 };
const BELT_Y     = 230;
const PILL_W     = 152;
const PILL_H     = 50;
const PILL_PITCH = PILL_W + 24;
const BELT_PAD   = 18;

// 3 visible slots; new plan enters slot 0 (closest to hub).
const FIRST_SLOT_X = 850;
const SLOT_POSITIONS = [
  FIRST_SLOT_X,
  FIRST_SLOT_X + PILL_PITCH,
  FIRST_SLOT_X + PILL_PITCH * 2,
];
const MAX_SLOTS = SLOT_POSITIONS.length;
// "Off-belt" x — the position a plan slides to before being removed
// (one pitch past the last visible slot). Used for the slide-off motion.
const OFFBELT_X = SLOT_POSITIONS[MAX_SLOTS - 1] + PILL_PITCH;
const SLIDE_DUR = 640;                   // ms — duration of the smooth right-slide

// Rails span from just before slot 0 to just past the last slot.
const BELT_START = SLOT_POSITIONS[0]               - PILL_W / 2 - BELT_PAD;
const BELT_END   = SLOT_POSITIONS[MAX_SLOTS - 1]   + PILL_W / 2 + BELT_PAD;

const INGREDIENTS_PER_BATCH = 3;

// ── Input glyph variants ─────────────────────────────────────────
function InputGlyph({ kind }) {
  switch (kind) {
    case "envelope":
      return (
        <g>
          <rect x="-14" y="-10" width="28" height="20" fill="none" stroke="currentColor" strokeWidth="1" />
          <path d="M -14 -10 L 0 2 L 14 -10" fill="none" stroke="currentColor" strokeWidth="1" />
        </g>
      );
    case "grid":
      return (
        <g>
          <rect x="-14" y="-14" width="28" height="28" fill="none" stroke="currentColor" strokeWidth="1" />
          <line x1="-14" y1="-5" x2="14" y2="-5" stroke="currentColor" strokeWidth="0.7" opacity="0.55" />
          <line x1="-14" y1="5"  x2="14" y2="5"  stroke="currentColor" strokeWidth="0.7" opacity="0.55" />
          <line x1="-5"  y1="-14" x2="-5" y2="14" stroke="currentColor" strokeWidth="0.7" opacity="0.55" />
          <line x1="5"   y1="-14" x2="5"  y2="14" stroke="currentColor" strokeWidth="0.7" opacity="0.55" />
        </g>
      );
    case "lines":
      return (
        <g>
          <rect x="-11" y="-15" width="22" height="30" fill="none" stroke="currentColor" strokeWidth="1" />
          <line x1="-7" y1="-9" x2="7"  y2="-9" stroke="currentColor" strokeWidth="0.9" opacity="0.6" />
          <line x1="-7" y1="-3" x2="7"  y2="-3" stroke="currentColor" strokeWidth="0.9" opacity="0.6" />
          <line x1="-7" y1="3"  x2="7"  y2="3"  stroke="currentColor" strokeWidth="0.9" opacity="0.6" />
          <line x1="-7" y1="9"  x2="3"  y2="9"  stroke="currentColor" strokeWidth="0.9" opacity="0.6" />
        </g>
      );
    case "ping":
      return (
        <g>
          <circle cx="0" cy="0" r="3"  fill="currentColor" />
          <circle cx="0" cy="0" r="8"  fill="none" stroke="currentColor" strokeWidth="1" opacity="0.65" />
          <circle cx="0" cy="0" r="14" fill="none" stroke="currentColor" strokeWidth="1" opacity="0.3" strokeDasharray="2 3" />
        </g>
      );
    case "bubble":
      return (
        <g>
          <rect x="-15" y="-11" width="30" height="18" rx="4" fill="none" stroke="currentColor" strokeWidth="1" />
          <path d="M -8 7 L -11 13 L -4 7" fill="none" stroke="currentColor" strokeWidth="1" />
          <circle cx="-6" cy="-2" r="1.2" fill="currentColor" />
          <circle cx="0"  cy="-2" r="1.2" fill="currentColor" />
          <circle cx="6"  cy="-2" r="1.2" fill="currentColor" />
        </g>
      );
    case "card":
      return (
        <g>
          <rect x="-14" y="-10" width="28" height="20" rx="2" fill="none" stroke="currentColor" strokeWidth="1" />
          <circle cx="-6" cy="-1" r="3" fill="none" stroke="currentColor" strokeWidth="0.9" />
          <line x1="1" y1="-4" x2="9" y2="-4" stroke="currentColor" strokeWidth="0.8" opacity="0.55" />
          <line x1="1" y1="0"  x2="9" y2="0"  stroke="currentColor" strokeWidth="0.8" opacity="0.55" />
          <line x1="-10" y1="5" x2="10" y2="5" stroke="currentColor" strokeWidth="0.8" opacity="0.4" />
        </g>
      );
    case "cal":
      return (
        <g>
          <rect x="-14" y="-12" width="28" height="24" fill="none" stroke="currentColor" strokeWidth="1" />
          <line x1="-14" y1="-5" x2="14" y2="-5" stroke="currentColor" strokeWidth="0.9" />
          <line x1="-9"  y1="-16" x2="-9" y2="-10" stroke="currentColor" strokeWidth="1" />
          <line x1="9"   y1="-16" x2="9"  y2="-10" stroke="currentColor" strokeWidth="1" />
          <circle cx="-5" cy="2" r="1.2" fill="currentColor" opacity="0.5" />
          <circle cx="5"  cy="2" r="1.2" fill="currentColor" opacity="0.5" />
          <circle cx="-5" cy="7" r="1.2" fill="currentColor" opacity="0.5" />
          <circle cx="5"  cy="7" r="1.2" fill="currentColor" opacity="0.5" />
        </g>
      );
    case "check":
      // QMS — a document with an inspection checkmark in its corner.
      return (
        <g>
          <rect x="-11" y="-15" width="22" height="30" fill="none" stroke="currentColor" strokeWidth="1" />
          <line x1="-7" y1="-9" x2="7" y2="-9" stroke="currentColor" strokeWidth="0.9" opacity="0.55" />
          <line x1="-7" y1="-4" x2="7" y2="-4" stroke="currentColor" strokeWidth="0.9" opacity="0.55" />
          <path d="M -5 5 L -1 9 L 6 1" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" />
        </g>
      );
    case "stack":
      // DB — three stacked discs (cylinder shorthand).
      return (
        <g>
          <ellipse cx="0" cy="-10" rx="14" ry="4" fill="none" stroke="currentColor" strokeWidth="1" />
          <path d="M -14 -10 L -14 10" stroke="currentColor" strokeWidth="1" fill="none" />
          <path d="M 14 -10 L 14 10" stroke="currentColor" strokeWidth="1" fill="none" />
          <path d="M -14 10 a 14 4 0 0 0 28 0" stroke="currentColor" strokeWidth="1" fill="none" />
          <path d="M -14 0 a 14 4 0 0 0 28 0" stroke="currentColor" strokeWidth="0.9" fill="none" opacity="0.55" />
          <path d="M -14 -5 a 14 4 0 0 0 28 0" stroke="currentColor" strokeWidth="0.9" fill="none" opacity="0.35" />
        </g>
      );
    default:
      return null;
  }
}

// Build the bezier d-string from an input glyph into the hub.
// Used both to draw the dashed flow path and to animate particles
// along it via CSS offset-path.
function inputPathD(inp) {
  const x1 = inp.x + 18;
  const y1 = inp.y;
  const x2 = HUB.x - HUB.rOuter + 2;
  const y2 = HUB.y;
  const cp1x = x1 + 50;
  const cp1y = y1;
  const cp2x = (x1 + x2) / 2;
  const cp2y = y2;
  return `M ${x1} ${y1} C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${x2} ${y2}`;
}

// Hub → first plan slot, straight-line path for the output particle.
const OUTPUT_PATH_D =
  `M ${HUB.x + HUB.rOuter - 2} ${BELT_Y} L ${FIRST_SLOT_X - PILL_W / 2 - 4} ${BELT_Y}`;

// ─────────────────────────────────────────────────────────────────────
// Mobile fallback — the desktop SVG scales below ~640px to the point
// where input labels are unreadable. On phones, render a vertical
// stack instead: 8 input chips → hub badge → one plan chip. Static,
// no animation. Conveys the same idea without competing with the
// vertical scroll of the page.
// ─────────────────────────────────────────────────────────────────────
function HovMobile() {
  const inputs = HOV_INPUTS.map((i) => i.label);
  return (
    <div className="hov-mobile" aria-label="INXM Orchestrator takes data from many systems and produces reusable Plans">
      <div className="hov-mobile__row hov-mobile__row--inputs">
        {inputs.map((label) => (
          <span key={label} className="hov-mobile__chip">{label}</span>
        ))}
      </div>
      <div className="hov-mobile__arrow" aria-hidden="true">
        <svg viewBox="0 0 14 28" width="14" height="28">
          <path d="M 7 2 L 7 24 M 2 19 L 7 24 L 12 19" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" />
        </svg>
      </div>
      <div className="hov-mobile__hub">
        <div className="hov-mobile__hub-ring" />
        <div className="hov-mobile__hub-ring hov-mobile__hub-ring--inner" />
        <div className="hov-mobile__hub-dot" />
        <span className="hov-mobile__hub-lbl">// ORCHESTRATOR</span>
      </div>
      <div className="hov-mobile__arrow" aria-hidden="true">
        <svg viewBox="0 0 14 28" width="14" height="28">
          <path d="M 7 2 L 7 24 M 2 19 L 7 24 L 12 19" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" />
        </svg>
      </div>
      <div className="hov-mobile__plan">
        <span className="hov-mobile__plan-dot" />
        <span className="hov-mobile__plan-slash">// </span>
        <span className="hov-mobile__plan-lbl">{PLAN_POOL[0]}</span>
      </div>
      <p className="hov-mobile__caption">
        Reusable plans, ready to run.
      </p>
    </div>
  );
}

function HeroOrchestratorView() {
  // Detect phone-sized viewports so we can ship a different
  // composition on mobile (vertical stack, no animation).
  const [isMobile, setIsMobile] = React.useState(() => {
    if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
    return window.matchMedia("(max-width: 640px)").matches;
  });
  React.useEffect(() => {
    if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
    const mq = window.matchMedia("(max-width: 640px)");
    const onChange = (e) => setIsMobile(e.matches);
    if (mq.addEventListener) mq.addEventListener("change", onChange);
    else mq.addListener(onChange);
    return () => {
      if (mq.removeEventListener) mq.removeEventListener("change", onChange);
      else mq.removeListener(onChange);
    };
  }, []);

  // Seed three plans already on the belt so the picture isn't empty
  // on first paint. `init: true` skips the pop-in animation for these.
  const [plans, setPlans] = React.useState(() => [
    { uid: "init-0", label: PLAN_POOL[2], slot: 0, init: true },
    { uid: "init-1", label: PLAN_POOL[1], slot: 1, init: true },
    { uid: "init-2", label: PLAN_POOL[0], slot: 2, init: true },
  ]);
  const [phase, setPhase] = React.useState("idle");
  const [activeInputs, setActiveInputs] = React.useState([]);
  // batchKey changes once per cycle so particle <circle>s remount
  // and replay their CSS offset-distance animation from 0%.
  const [batchKey, setBatchKey] = React.useState(0);
  // 0 → 1 progress of the right-slide animation. Eased outside this
  // state — it's the eased value used directly for interpolation.
  const [slideProgress, setSlideProgress] = React.useState(1);

  React.useEffect(() => {
    let cancelled = false;
    let timer;
    let raf;
    let counter = PLAN_POOL.length / 2 | 0; // start a few in

    const step = () => {
      if (cancelled) return;

      // PHASE 1 · mixing — three input flow lines pulse and particles
      //                     travel from each chosen input into the hub.
      setBatchKey((k) => k + 1);
      setPhase("mixing");
      const batch = [];
      for (let i = 0; i < INGREDIENTS_PER_BATCH; i++) {
        batch.push(HOV_INPUTS[(counter * INGREDIENTS_PER_BATCH + i) % HOV_INPUTS.length].id);
      }
      setActiveInputs(batch);

      timer = setTimeout(() => {
        if (cancelled) return;

        // PHASE 2 · working — hub pulses harder.
        setPhase("working");

        timer = setTimeout(() => {
          if (cancelled) return;

          // PHASE 3a · slide — each plan smoothly glides one slot to
          //                    the right via RAF-driven interpolation.
          //                    Plans that move off-belt are KEPT during
          //                    the slide so they animate offscreen,
          //                    then removed after the animation ends.
          setPlans((prev) =>
            prev.map((p) => ({
              ...p,
              slidingFromSlot: p.slot,
              slot: p.slot + 1,
            }))
          );
          setSlideProgress(0);
          const slideStart = performance.now();
          const animateSlide = (now) => {
            if (cancelled) return;
            const t = Math.min(1, (now - slideStart) / SLIDE_DUR);
            // ease-out cubic
            const eased = 1 - Math.pow(1 - t, 3);
            setSlideProgress(eased);
            if (t < 1) {
              raf = requestAnimationFrame(animateSlide);
            } else {
              // Clean up: drop off-belt plans, clear slidingFromSlot.
              setPlans((prev) =>
                prev
                  .filter((p) => p.slot < MAX_SLOTS)
                  .map((p) => ({ ...p, slidingFromSlot: undefined }))
              );
            }
          };
          raf = requestAnimationFrame(animateSlide);

          timer = setTimeout(() => {
            if (cancelled) return;

            // PHASE 3b · pop — new plan enters slot 0; an output
            //                  particle travels hub → slot 0 in sync.
            setPhase("popping");
            const newLabel = PLAN_POOL[counter % PLAN_POOL.length];
            const newUid = "p-" + counter;
            counter++;
            setPlans((prev) => [
              { uid: newUid, label: newLabel, slot: 0, init: false },
              ...prev,
            ]);

            // PHASE 4 · settle, then loop.
            timer = setTimeout(() => {
              if (cancelled) return;
              setPhase("idle");
              setActiveInputs([]);
              timer = setTimeout(step, 1200);
            }, 800);
          }, 720);
        }, 900);
      }, 1100);
    };

    // start after a short delay so the seeded plans render first
    timer = setTimeout(step, 900);

    return () => {
      cancelled = true;
      clearTimeout(timer);
      if (raf) cancelAnimationFrame(raf);
    };
  }, []);

  // Mobile fallback — hero illustration is hidden entirely on phones.
  // Returns null so even if the CSS is stale, nothing renders.
  if (isMobile) return null;

  return (
    <div className="hov-flow" role="img" aria-label="INXM Orchestrator: data ingredients flow in, are processed, and a new Plan pops out on the pipeline">
      <svg
        viewBox="0 0 1280 460"
        className="hov-flow__svg"
        aria-hidden="true"
        preserveAspectRatio="xMidYMid meet"
      >
        {/* ── INPUT FLOW · curve from each glyph into the hub ── */}
        {HOV_INPUTS.map((inp, i) => {
          const isActive = activeInputs.includes(inp.id);
          return (
            <path
              key={"in" + inp.id}
              d={inputPathD(inp)}
              fill="none"
              className={
                "hov-flow__path hov-flow__path--in" +
                (isActive ? " is-active" : "")
              }
              strokeDasharray="3 4"
              style={{ animationDelay: `${(i * 0.35).toFixed(2)}s` }}
            />
          );
        })}

        {/* ── INPUT PARTICLES · travel from chosen inputs to hub ── */}
        {phase === "mixing" &&
          activeInputs.map((id, j) => {
            const inp = HOV_INPUTS.find((x) => x.id === id);
            if (!inp) return null;
            const delay = (j * 0.14).toFixed(2) + "s";
            return (
              <circle
                key={`particle-${batchKey}-${id}`}
                cx="0"
                cy="0"
                r="4.5"
                className="hov-flow__particle hov-flow__particle--in"
                style={{ animationDelay: delay }}
              >
                <animateMotion
                  dur="0.98s"
                  begin={delay}
                  fill="freeze"
                  path={inputPathD(inp)}
                  calcMode="spline"
                  keySplines="0.35 0.05 0.25 1"
                  keyTimes="0;1"
                />
              </circle>
            );
          })}

        {/* ── INPUT GLYPHS · varied kinds of data ── */}
        {HOV_INPUTS.map((inp) => (
          <g
            key={inp.id}
            transform={`translate(${inp.x} ${inp.y})`}
            className={"hov-flow__input" + (activeInputs.includes(inp.id) ? " is-active" : "")}
          >
            <InputGlyph kind={inp.kind} />
            <text x="0" y="32" textAnchor="middle" className="hov-flow__lbl">
              {inp.label}
            </text>
          </g>
        ))}

        {/* ── HUB · concentric rings + accent center; pulses when "working" ── */}
        <g
          transform={`translate(${HUB.x} ${HUB.y})`}
          className={"hov-flow__hub is-" + phase}
        >
          <circle cx="0" cy="0" r={HUB.rOuter} fill="none" className="hov-flow__ring hov-flow__ring--outer" strokeDasharray="2 6" />
          <circle cx="0" cy="0" r={HUB.rMid}   fill="none" className="hov-flow__ring hov-flow__ring--mid" />
          <circle cx="0" cy="0" r={HUB.rInner} fill="none" className="hov-flow__ring hov-flow__ring--accent" />
          <circle cx="0" cy="0" r="6" className="hov-flow__hub-dot" />
          <text x="0" y={HUB.rOuter + 28} textAnchor="middle" className="hov-flow__lbl hov-flow__lbl--hub">
            ORCHESTRATOR
          </text>
        </g>

        {/* ── BRIDGE · hub → belt start ── */}
        <path
          d={`M ${HUB.x + HUB.rOuter - 2} ${HUB.y} L ${BELT_START} ${BELT_Y}`}
          fill="none"
          className="hov-flow__path hov-flow__path--bridge"
        />

        {/* ── OUTPUT PARTICLE · hub → slot 0 when a plan pops ── */}
        {phase === "popping" && (
          <circle
            key={`out-particle-${batchKey}`}
            cx="0"
            cy="0"
            r="5"
            className="hov-flow__particle hov-flow__particle--out"
          >
            <animateMotion
              dur="0.58s"
              fill="freeze"
              path={OUTPUT_PATH_D}
              calcMode="spline"
              keySplines="0.4 0 0.2 1"
              keyTimes="0;1"
            />
          </circle>
        )}

        {/* ── BELT · two faint rails + delivery arrow (no continuous animation) ── */}
        <g className="hov-flow__belt">
          <line x1={BELT_START} y1={BELT_Y - 34} x2={BELT_END} y2={BELT_Y - 34} className="hov-flow__rail" />
          <line x1={BELT_START} y1={BELT_Y + 34} x2={BELT_END} y2={BELT_Y + 34} className="hov-flow__rail" />
          <g transform={`translate(${BELT_END + 14} ${BELT_Y})`}>
            <path d="M 0 -7 L 13 0 L 0 7" fill="none" className="hov-flow__arrow" />
          </g>
        </g>

        {/* ── PLANS · discrete state-driven slots ── */}
        {plans.map((p) => {
          // Compute x by interpolating from `slidingFromSlot` (if set)
          // to current `slot`, using the global slideProgress. Plans
          // that sit at slot >= MAX_SLOTS animate off-belt to OFFBELT_X.
          const toX = p.slot < MAX_SLOTS ? SLOT_POSITIONS[p.slot] : OFFBELT_X;
          let x = toX;
          if (p.slidingFromSlot != null && slideProgress < 1) {
            const fromX = p.slidingFromSlot < MAX_SLOTS
              ? SLOT_POSITIONS[p.slidingFromSlot]
              : OFFBELT_X;
            x = fromX + (toX - fromX) * slideProgress;
          }
          return (
            <g
              key={p.uid}
              className="hov-flow__plan-slot"
              transform={`translate(${x} ${BELT_Y})`}
            >
              <g
                className={"hov-flow__plan-pop" + (p.init ? " is-init" : "")}
              >
                <rect
                  x={-PILL_W / 2}
                  y={-PILL_H / 2}
                  width={PILL_W}
                  height={PILL_H}
                  rx={PILL_H / 2}
                  ry={PILL_H / 2}
                  className={"hov-flow__pill" + (p.slot === 0 ? " is-fresh" : "")}
                />
                <circle
                  cx={-PILL_W / 2 + 16}
                  cy="0"
                  r="3"
                  className={"hov-flow__pill-dot" + (p.slot === 0 ? " is-fresh" : "")}
                />
                <text
                  x={-PILL_W / 2 + 28}
                  y="0"
                  dominantBaseline="middle"
                  className="hov-flow__pill-lbl"
                >
                  <tspan className="hov-flow__pill-slash">// </tspan>
                  {p.label}
                </text>
              </g>
            </g>
          );
        })}
      </svg>
    </div>
  );
}

window.HeroOrchestratorView = HeroOrchestratorView;
