// line.jsx — atmospheric line decorator
// Substitute for the WebGL line in the real site. SVG path with
// gaussian-blur "bloom" filter. Three flavors:
//   <HeroLine presence />  — follows cursor with smooth lag (or static)
//   <BranchSvg />          — branched threads for Cases block
//   <FinalLines />         — radiate outward for the final CTA
//   <AmbientLines />       — ambient curves spanning the whole page
//                            (rendered only when presence = "everywhere")

const { useEffect, useRef, useState } = React;

function HeroLine({ presence = "pulse" }) {
  const ref = useRef(null);

  useEffect(() => {
    // Static sweeping curve — no longer follows the cursor.
    const draw = () => {
      if (!ref.current) return;
      const cx = window.innerWidth / 2;
      const cy = window.innerHeight / 2;
      ref.current.setAttribute(
        "d",
        `M ${cx - 600} ${cy - 320} C ${cx - 280} ${cy - 80}, ${cx + 280} ${cy + 80}, ${cx + 600} ${cy + 320}`
      );
    };
    draw();
    window.addEventListener("resize", draw);
    return () => window.removeEventListener("resize", draw);
  }, [presence]);

  return (
    <svg className="line-canvas" preserveAspectRatio="none">
      <defs>
        <filter id="bloom" x="-50%" y="-50%" width="200%" height="200%">
          <feGaussianBlur stdDeviation="3" result="b"/>
          <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
        </filter>
      </defs>
      {/* Outer thick "halo" line + inner thin bright core */}
      <path
        ref={ref}
        stroke="#7a4ee0"
        strokeWidth="5"
        fill="none"
        filter="url(#bloom)"
        opacity="0.95"
        strokeLinecap="round"
      />
    </svg>
  );
}

// HeroLines — a "scene" of decorative lines composed inside the hero only.
// Three styles, swappable from Tweaks. Designed to land at the bottom-center
// of the hero so the SiteLine in About picks them up.
function HeroLines({ style = "trail" }) {
  if (style === "off") return null;

  // "trail" — single sweeping S-curve plus a faint twin behind it (current vibe)
  if (style === "trail") {
    return (
      <svg className="hero-lines hero-lines-trail" viewBox="0 0 1200 800"
           preserveAspectRatio="none" aria-hidden="true">
        <defs>
          <filter id="hl-b" x="-50%" y="-50%" width="200%" height="200%">
            <feGaussianBlur stdDeviation="2"/>
          </filter>
        </defs>
        <g fill="none" filter="url(#hl-b)" strokeLinecap="round">
          <path className="hl-twin" stroke="#f5f5f5" strokeWidth="1.4"
                opacity="0.35"
                d="M 1100 80 C 950 250, 850 380, 720 460 S 480 600, 600 800"/>
          <path className="hl-main" stroke="#7a4ee0" strokeWidth="3"
                d="M 1140 60 C 980 240, 880 380, 740 470 S 480 620, 600 800"/>
        </g>
      </svg>
    );
  }

  // "descend" — 3 curves descending from top edge, converging at x=600 bottom,
  // i.e. the start of the SiteLine. Reads as the line "appearing from above".
  // Base paths stay solid; a comet pulse rides each path.
  if (style === "descend") {
    const D1 = "M 200 -10 C 240 200, 420 460, 600 800";
    const D2 = "M 800 -10 C 760 220, 700 480, 600 800";
    const D3 = "M 1100 -10 C 1000 240, 800 500, 600 800";
    return (
      <svg className="hero-lines hero-lines-descend" viewBox="0 0 1200 800"
           preserveAspectRatio="none" aria-hidden="true">
        <defs>
          <filter id="hl-d" x="-50%" y="-50%" width="200%" height="200%">
            <feGaussianBlur stdDeviation="2.5"/>
          </filter>
        </defs>
        <g fill="none" filter="url(#hl-d)" strokeLinecap="round">
          {/* Base solid lines */}
          <path className="hl-base" stroke="#7a4ee0" strokeWidth="2"
                opacity="0.55" d={D1}/>
          <path className="hl-base" stroke="#7a4ee0" strokeWidth="2.8"
                opacity="0.7" d={D2}/>
          <path className="hl-base" stroke="#f5f5f5" strokeWidth="1.1"
                opacity="0.30" d={D3}/>
          {/* Comet pulses riding each line */}
          <path className="hl-d hl-d-1" stroke="#7a4ee0" strokeWidth="3.2" d={D1}/>
          <path className="hl-d hl-d-2" stroke="#7a4ee0" strokeWidth="4" d={D2}/>
          <path className="hl-d hl-d-3" stroke="#f5f5f5" strokeWidth="2"
                opacity="0.7" d={D3}/>
        </g>
      </svg>
    );
  }

  // "orbit" — elliptical loop around the logo + tail exiting bottom-center
  if (style === "orbit") {
    return (
      <svg className="hero-lines hero-lines-orbit" viewBox="0 0 1200 800"
           preserveAspectRatio="none" aria-hidden="true">
        <defs>
          <filter id="hl-o" x="-50%" y="-50%" width="200%" height="200%">
            <feGaussianBlur stdDeviation="2.5"/>
          </filter>
        </defs>
        <g fill="none" filter="url(#hl-o)" strokeLinecap="round" strokeWidth="2.5">
          <path className="hl-orbit" stroke="#7a4ee0"
                d="M 600 200 C 320 200, 200 360, 320 480 C 440 600, 760 600, 880 480 C 1000 360, 880 200, 600 200 Z"/>
          <path className="hl-orbit-tail" stroke="#7a4ee0"
                d="M 600 600 C 600 680, 600 740, 600 800"/>
          <path className="hl-orbit-ghost" stroke="#f5f5f5" strokeWidth="1.2"
                opacity="0.35"
                d="M 600 220 C 340 220, 240 360, 340 470 C 460 580, 740 580, 860 470 C 960 360, 860 220, 600 220 Z"/>
        </g>
      </svg>
    );
  }

  // "weave" — 3 horizontal-ish wavy lines weaving across the hero
  if (style === "weave") {
    return (
      <svg className="hero-lines hero-lines-weave" viewBox="0 0 1200 800"
           preserveAspectRatio="none" aria-hidden="true">
        <defs>
          <filter id="hl-w" x="-50%" y="-50%" width="200%" height="200%">
            <feGaussianBlur stdDeviation="2.5"/>
          </filter>
        </defs>
        <g fill="none" filter="url(#hl-w)" strokeLinecap="round" strokeWidth="2.5">
          <path className="hl-w hl-w-1" stroke="#7a4ee0"
                d="M -50 280 C 220 200, 380 360, 600 320 S 980 240, 1250 360"/>
          <path className="hl-w hl-w-2" stroke="#7a4ee0" strokeWidth="3.2"
                d="M -50 480 C 220 380, 460 540, 720 460 S 1020 520, 1250 420"/>
          <path className="hl-w hl-w-3" stroke="#f5f5f5" strokeWidth="1.2"
                opacity="0.4"
                d="M -50 660 C 240 580, 460 700, 720 620 S 1020 700, 1250 600"/>
          {/* converge to bottom-center where SiteLine begins */}
          <path className="hl-w-converge" stroke="#7a4ee0" strokeWidth="2"
                d="M 600 460 C 600 580, 600 680, 600 800" opacity="0.7"/>
        </g>
      </svg>
    );
  }

  return null;
}

// CursorGlow — a soft purple drop that follows the cursor with lag.
// Brighter in the hero, dimmer everywhere else (CSS handles dim via
// the .cursor-glow.outside class toggled below).
function CursorGlow() {
  const ref = useRef(null);
  const pos = useRef({ x: -200, y: -200 });
  const target = useRef({ x: -200, y: -200 });
  const visible = useRef(false);

  useEffect(() => {
    const onMove = (e) => {
      target.current.x = e.clientX;
      target.current.y = e.clientY;
      if (!visible.current) {
        pos.current.x = e.clientX;
        pos.current.y = e.clientY;
        visible.current = true;
      }
      // Detect whether we're inside hero (in viewport coords — covers
      // "hero scrolled away" without measuring layout).
      const hero = document.getElementById("hero");
      let inHero = false;
      if (hero) {
        const r = hero.getBoundingClientRect();
        inHero = e.clientY >= r.top && e.clientY <= r.bottom;
      }
      if (ref.current) {
        ref.current.classList.toggle("in-hero", inHero);
        ref.current.classList.toggle("outside", !inHero);
      }
    };
    const onLeave = () => {
      if (ref.current) ref.current.classList.add("is-hidden");
    };
    const onEnter = () => {
      if (ref.current) ref.current.classList.remove("is-hidden");
    };
    window.addEventListener("mousemove", onMove);
    document.addEventListener("mouseleave", onLeave);
    document.addEventListener("mouseenter", onEnter);

    let raf;
    const tick = () => {
      pos.current.x += (target.current.x - pos.current.x) * 0.12;
      pos.current.y += (target.current.y - pos.current.y) * 0.12;
      if (ref.current) {
        ref.current.style.transform =
          `translate3d(${pos.current.x}px, ${pos.current.y}px, 0) translate(-50%, -50%)`;
      }
      raf = requestAnimationFrame(tick);
    };
    tick();
    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener("mousemove", onMove);
      document.removeEventListener("mouseleave", onLeave);
      document.removeEventListener("mouseenter", onEnter);
    };
  }, []);

  return <div ref={ref} className="cursor-glow is-hidden" aria-hidden="true" />;
}

// Ambient lines that bleed through the whole page — for presence "everywhere"
function AmbientLines() {
  return (
    <svg
      className="ambient-lines"
      aria-hidden="true"
      viewBox="0 0 100 100"
      preserveAspectRatio="none"
    >
      <defs>
        <filter id="amb-b" x="-50%" y="-50%" width="200%" height="200%">
          <feGaussianBlur stdDeviation="0.3"/>
        </filter>
      </defs>
      <g fill="none" strokeWidth="0.15" filter="url(#amb-b)" opacity="0.55"
         vectorEffect="non-scaling-stroke">
        <path stroke="#7a4ee0" d="M -2 8 C 25 12, 45 18, 70 14 S 105 22, 110 28"/>
        <path stroke="#7a4ee0" d="M -2 24 C 22 30, 52 22, 78 32 S 102 38, 110 36"/>
        <path stroke="#f5f5f5" d="M -2 42 C 18 48, 38 40, 62 50 S 92 56, 110 52" opacity="0.4"/>
        <path stroke="#7a4ee0" d="M -2 58 C 28 64, 58 56, 82 66 S 105 72, 110 68"/>
        <path stroke="#7a4ee0" d="M -2 76 C 24 80, 50 74, 75 82 S 100 88, 110 84"/>
        <path stroke="#f5f5f5" d="M -2 92 C 20 96, 45 90, 72 98 S 100 102, 110 100" opacity="0.4"/>
        <path stroke="#7a4ee0" d="M 30 -2 C 32 15, 28 35, 35 55 S 30 92, 32 110" opacity="0.4"/>
        <path stroke="#7a4ee0" d="M 70 -2 C 68 18, 74 38, 66 58 S 72 92, 68 110" opacity="0.4"/>
      </g>
    </svg>
  );
}

// Branching diagram, used inside the Cases block.
// columns: 3 per row, 2 rows → 6 verticals
function BranchSvg() {
  return (
    <svg className="verticals-svg" viewBox="0 0 1200 600" preserveAspectRatio="none" aria-hidden="true">
      <defs>
        <filter id="bb-p" x="-50%" y="-50%" width="200%" height="200%">
          <feGaussianBlur stdDeviation="2.5"/>
        </filter>
        <filter id="bb-w" x="-50%" y="-50%" width="200%" height="200%">
          <feGaussianBlur stdDeviation="2"/>
        </filter>
      </defs>
      <g fill="none" strokeWidth="1.8">
        {/* source into hub */}
        <path d="M 600 -10 V 100" stroke="#7a4ee0" filter="url(#bb-p)"/>
        <circle cx="600" cy="100" r="2.5" fill="#7a4ee0" filter="url(#bb-p)"/>
        {/* row 1 — three threads to 200/600/1000 x ~150y */}
        <path d="M 600 100 C 600 130, 250 130, 200 150" stroke="#7a4ee0" filter="url(#bb-p)"/>
        <path d="M 600 100 C 600 130, 600 130, 600 150" stroke="#f5f5f5" filter="url(#bb-w)" opacity="0.95"/>
        <path d="M 600 100 C 600 130, 950 130, 1000 150" stroke="#7a4ee0" filter="url(#bb-p)"/>
        {/* connectors row1 → row2 down past verticals */}
        <path d="M 200 220 V 350 C 200 380, 250 400, 200 450" stroke="#f5f5f5" filter="url(#bb-w)" opacity="0.9"/>
        <path d="M 600 220 V 350 C 600 380, 580 400, 600 450" stroke="#7a4ee0" filter="url(#bb-p)"/>
        <path d="M 1000 220 V 350 C 1000 380, 950 400, 1000 450" stroke="#f5f5f5" filter="url(#bb-w)" opacity="0.9"/>
      </g>
    </svg>
  );
}

function FinalLines() {
  return (
    <div className="final-lines" aria-hidden="true">
      <svg viewBox="0 0 1200 600" preserveAspectRatio="none">
        <defs>
          <filter id="fl-b" x="-50%" y="-50%" width="200%" height="200%">
            <feGaussianBlur stdDeviation="2"/>
          </filter>
        </defs>
        <g stroke="#7a4ee0" strokeWidth="1.4" fill="none" filter="url(#fl-b)" opacity="0.55">
          <path d="M 600 360 C 480 290, 250 240, 0 220"/>
          <path d="M 600 360 C 720 290, 950 240, 1200 220"/>
          <path d="M 600 360 C 500 330, 200 320, 0 310"/>
          <path d="M 600 360 C 700 330, 1000 320, 1200 310"/>
          <path d="M 600 360 C 520 380, 220 420, 0 440"/>
          <path d="M 600 360 C 680 380, 980 420, 1200 440"/>
          <path d="M 600 360 V 0" opacity="0.4"/>
          <path d="M 600 360 V 600" opacity="0.4"/>
        </g>
      </svg>
    </div>
  );
}

// SiteLine — vertical wavy line that draws progressively as you scroll
// past the hero. Spans from just-below-hero to the bottom of the page.
function SiteLine() {
  const pathRef = useRef(null);
  const twinRef = useRef(null);
  const [bounds, setBounds] = useState({ top: 0, height: 600 });
  const [pathLen, setPathLen] = useState(0);
  const [twinLen, setTwinLen] = useState(0);
  const [drawn, setDrawn] = useState(0);
  const [twinDrawn, setTwinDrawn] = useState(0);
  const [maskCss, setMaskCss] = useState(null);
  const [casesRange, setCasesRange] = useState(null);

  useEffect(() => {
    const measure = () => {
      const heroH = window.innerHeight;
      const total = document.body.scrollHeight;
      const newBounds = { top: heroH, height: Math.max(total - heroH, 600) };
      setBounds(newBounds);

      const scrollY = window.pageYOffset || document.documentElement.scrollTop || 0;
      const measureSec = (id) => {
        const el = document.getElementById(id);
        if (!el) return null;
        const r = el.getBoundingClientRect();
        return {
          y1: r.top + scrollY - newBounds.top,
          y2: r.top + scrollY - newBounds.top + r.height,
        };
      };
      const cR = measureSec("cases");
      const wR = measureSec("why");
      setCasesRange(cR);

      // Fade-out mask: the line goes opaque from top until the start of
      // the Why Traffy block, then fades to fully transparent over ~200px.
      if (wR && newBounds.height > 0) {
        const fadeStart = (wR.y1 / newBounds.height) * 100;
        const fadeEnd = Math.min(100, ((wR.y1 + 220) / newBounds.height) * 100);
        const mask = `linear-gradient(180deg, black 0%, black ${Math.max(0, fadeStart - 1)}%, transparent ${fadeEnd}%, transparent 100%)`;
        setMaskCss(mask);
      } else {
        setMaskCss(null);
      }
    };
    measure();
    const ro = new ResizeObserver(measure);
    ro.observe(document.body);
    window.addEventListener("resize", measure);
    const t1 = setTimeout(measure, 400);
    const t2 = setTimeout(measure, 1500);
    return () => {
      ro.disconnect();
      window.removeEventListener("resize", measure);
      clearTimeout(t1); clearTimeout(t2);
    };
  }, []);

  // Re-measure path lengths when geometry changes
  useEffect(() => {
    if (pathRef.current) setPathLen(pathRef.current.getTotalLength());
    if (twinRef.current) setTwinLen(twinRef.current.getTotalLength());
    else setTwinLen(0);
  }, [bounds.height, casesRange]);

  // Scroll progress
  useEffect(() => {
    let raf;
    const onScroll = () => {
      const start = bounds.top * 0.5;
      const end = bounds.top + bounds.height * 0.92;
      const cur = window.scrollY + window.innerHeight * 0.55;
      const frac = Math.max(0, Math.min(1, (cur - start) / (end - start)));
      const eased = 1 - Math.pow(1 - frac, 2.2);
      setDrawn(eased);

      // Twin progress tied to scroll through Cases: draws as user scrolls.
      if (casesRange) {
        const cTop = bounds.top + casesRange.y1;
        const cBot = bounds.top + casesRange.y2;
        const cFrac = Math.max(0, Math.min(1, (cur - cTop) / Math.max(1, cBot - cTop)));
        const cEased = 1 - Math.pow(1 - cFrac, 2);
        setTwinDrawn(cEased);
      }
    };
    const scheduled = () => { if (!raf) raf = requestAnimationFrame(() => { raf = null; onScroll(); }); };
    onScroll();
    window.addEventListener("scroll", scheduled, { passive: true });
    return () => { window.removeEventListener("scroll", scheduled); if (raf) cancelAnimationFrame(raf); };
  }, [bounds, casesRange]);

  // Main path — starts at x=600 (where hero lines converge), waves through
  // sections, returns to center axis from cases onward.
  const path = React.useMemo(() => {
    const segs = 8;
    const h = bounds.height;
    const yStep = h / segs;
    //                  0    1    2    3    4    5    6    7    8
    //                 about     services  more   creat cases why ctct end
    const xs = [600, 400, 860, 320, 760, 600, 600, 600, 600];
    let d = `M ${xs[0]} 0`;
    for (let i = 1; i <= segs; i++) {
      const x1 = xs[i] ?? 600;
      const x0 = xs[i - 1] ?? 600;
      const y0 = (i - 1) * yStep;
      const y1 = i * yStep;
      const cy0 = y0 + yStep * 0.35;
      const cy1 = y1 - yStep * 0.35;
      d += ` C ${x0} ${cy0}, ${x1} ${cy1}, ${x1} ${y1}`;
    }
    return d;
  }, [bounds.height]);

  // Single-thread path: the line no longer splits through Cases. Twin path
  // disabled so only the main wave runs the full height.
  const twinPath = null;

  const offset = pathLen > 0 ? pathLen * (1 - drawn) : 0;
  const twinOffset = twinLen > 0 ? twinLen * (1 - twinDrawn) : 0;

  return (
    <div
      className="site-line"
      aria-hidden="true"
      style={{
        top: bounds.top,
        height: bounds.height,
        ...(maskCss ? { WebkitMaskImage: maskCss, maskImage: maskCss } : null),
      }}
    >
      <svg viewBox={`0 0 1200 ${bounds.height}`} preserveAspectRatio="none">
        <path
          ref={pathRef}
          d={path}
          stroke="#7a4ee0"
          strokeWidth="2.5"
          fill="none"
          strokeLinecap="round"
          vectorEffect="non-scaling-stroke"
          strokeDasharray={pathLen || undefined}
          strokeDashoffset={offset}
          style={{ transition: "stroke-dashoffset 0.9s cubic-bezier(.16,1,.3,1)" }}
        />
        {twinPath && (
          <path
            ref={twinRef}
            d={twinPath}
            stroke="#7a4ee0"
            strokeWidth="2"
            fill="none"
            strokeLinecap="round"
            vectorEffect="non-scaling-stroke"
            strokeDasharray={twinLen || undefined}
            strokeDashoffset={twinOffset}
            opacity="0.85"
            style={{ transition: "stroke-dashoffset 0.6s cubic-bezier(.16,1,.3,1)" }}
          />
        )}
      </svg>
    </div>
  );
}

Object.assign(window, { HeroLine, HeroLines, BranchSvg, FinalLines, AmbientLines, SiteLine, CursorGlow });
