const { useEffect, useMemo, useState } = React;

const SG_PATH = "M 140,503.6 L 147.9,432.7 L 195.1,372.8 L 266,298.8 L 336.9,251.5 L 376.3,223.2 L 431.5,212.1 L 494.5,196.4 L 557.5,196.4 L 612.6,212.1 L 675.7,246.8 L 738.7,262.6 L 793.8,287.8 L 833.2,306.7 L 856.8,325.6 L 860,357.1 L 849,388.6 L 822.2,417 L 770.2,432.7 L 722.9,440.6 L 675.7,445.3 L 620.5,448.5 L 565.4,451.6 L 557.5,472.1 L 533.9,495.7 L 494.5,498.9 L 439.3,487.9 L 376.3,476.8 L 321.2,461.1 L 273.9,451.6 L 226.7,456.3 L 187.3,472.1 L 155.8,487.9 L 140,503.6 Z";

function formatAgo(seconds) {
  if (seconds < 60) return seconds + "s";
  if (seconds < 3600) return Math.round(seconds / 60) + "m";
  return Math.round(seconds / 3600) + "h";
}

function statusColor(status, accent) {
  if (status === "watch") return "#FFC23D";
  if (status === "delayed") return "#FF8A5B";
  if (status === "idle") return "rgba(255,255,255,0.58)";
  return accent;
}

function clusterGlyph(kind, color) {
  if (kind === "battery-present") {
    return (
      <svg viewBox="0 0 18 18" width="18" height="18" aria-hidden="true">
        <rect x="4" y="4" width="8" height="10" rx="1.8" fill="none" stroke={color} strokeWidth="1.2" />
        <rect x="12.5" y="7" width="1.5" height="4" rx="0.7" fill={color} />
      </svg>
    );
  }
  if (kind === "ev-present") {
    return (
      <svg viewBox="0 0 18 18" width="18" height="18" aria-hidden="true">
        <circle cx="9" cy="9" r="4.5" fill="none" stroke={color} strokeWidth="1.2" />
        <path d="M9 4.5v2.4M9 11.1v2.4M4.5 9h2.4M11.1 9h2.4" stroke={color} strokeWidth="1" strokeLinecap="round" />
      </svg>
    );
  }
  if (kind === "industrial") {
    return (
      <svg viewBox="0 0 18 18" width="18" height="18" aria-hidden="true">
        <path d="M4 13V6.8l3.1 1.7V6.1l3.2 1.8V5.5L14 7.6V13Z" fill="none" stroke={color} strokeWidth="1.2" strokeLinejoin="round" />
      </svg>
    );
  }
  return (
    <svg viewBox="0 0 18 18" width="18" height="18" aria-hidden="true">
      <circle cx="9" cy="9" r="4.8" fill="none" stroke={color} strokeWidth="1.2" />
      <circle cx="9" cy="9" r="1.8" fill={color} />
    </svg>
  );
}

function MiniTrend({ points, accent }) {
  if (!points || !points.length) return null;

  const width = 220;
  const height = 72;
  const pad = 6;
  const min = Math.min.apply(null, points);
  const max = Math.max.apply(null, points);
  const range = Math.max(1, max - min);
  const coords = points.map(function toCoord(value, index) {
    const x = pad + (index / (points.length - 1)) * (width - pad * 2);
    const y = height - pad - ((value - min) / range) * (height - pad * 2);
    return [x, y];
  });
  const path = coords.map(function toPath(point, index) {
    return (index ? "L" : "M") + point[0].toFixed(1) + "," + point[1].toFixed(1);
  }).join(" ");
  const area = path + " L " + coords[coords.length - 1][0].toFixed(1) + "," + (height - pad) + " L " + coords[0][0].toFixed(1) + "," + (height - pad) + " Z";
  const last = coords[coords.length - 1];

  return (
    <svg viewBox={"0 0 " + width + " " + height} width="100%" height="72" preserveAspectRatio="none">
      <defs>
        <linearGradient id="heroTrendArea" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor={accent} stopOpacity="0.24" />
          <stop offset="100%" stopColor={accent} stopOpacity="0" />
        </linearGradient>
      </defs>
      {[0.25, 0.5, 0.75].map(function line(level, index) {
        return <line key={index} x1="0" x2={width} y1={height * level} y2={height * level} stroke="rgba(255,255,255,0.05)" strokeDasharray="2 4" />;
      })}
      <path d={area} fill="url(#heroTrendArea)" />
      <path d={path} stroke={accent} strokeWidth="1.5" fill="none" />
      <circle cx={last[0]} cy={last[1]} r="2.8" fill={accent} />
    </svg>
  );
}

function NetworkInspector({ cluster, networkData, accent }) {
  if (!cluster) return null;
  const color = statusColor(cluster.status, accent);
  const mixEntries = [
    ["Solar", cluster.mix.solar],
    ["Battery", cluster.mix.battery],
    ["EV", cluster.mix.ev],
    ["Weather", cluster.mix.weather],
  ];

  return (
    <div className="hero-inspector">
      <div className="hero-inspector-top">
        <div>
          <div className="hero-inspector-label">SELECTED CLUSTER</div>
          <h3>{cluster.label}</h3>
          <p>{cluster.anonymized_label}</p>
        </div>
        <div className="hero-status-chip" style={{ color: color, borderColor: color + "55", background: color + "14" }}>
          {cluster.status}
        </div>
      </div>

      <div className="hero-inspector-block">
        <div className="hero-inspector-metrics">
          <div className="hero-inspector-metric">
            <span>ACTIVITY</span>
            <strong>{cluster.activity_index}<small>/100</small></strong>
          </div>
          <div className="hero-inspector-metric">
            <span>CELLS</span>
            <strong>{cluster.cells_reporting}</strong>
          </div>
          <div className="hero-inspector-metric">
            <span>FRESHNESS</span>
            <strong>{formatAgo(cluster.freshness_sec)}</strong>
          </div>
          <div className="hero-inspector-metric">
            <span>1H DELTA</span>
            <strong style={{ color: cluster.change_1h_pct >= 0 ? accent : "#FFC23D" }}>
              {cluster.change_1h_pct >= 0 ? "+" : ""}{cluster.change_1h_pct}%
            </strong>
          </div>
        </div>
      </div>

      <div className="hero-inspector-block">
        <div className="hero-inspector-subhead">
          <span>OBSERVATION MIX</span>
          {clusterGlyph(cluster.kind, color)}
        </div>
        <div className="hero-mix-list">
          {mixEntries.map(function renderMix(entry) {
            const label = entry[0];
            const value = entry[1];
            return (
              <div key={label} className="hero-mix-row">
                <span>{label}</span>
                <div className="hero-mix-bar">
                  <div style={{ width: Math.max(6, value) + "%", background: accent }} />
                </div>
                <strong>{value}%</strong>
              </div>
            );
          })}
        </div>
      </div>

      <div className="hero-inspector-block">
        <div className="hero-inspector-subhead">
          <span>RECENT TREND</span>
          <span>{cluster.observation_band}</span>
        </div>
        <MiniTrend points={cluster.trend_points} accent={accent} />
      </div>

      <div className="hero-inspector-block hero-inspector-note">
        <div className="hero-inspector-subhead">
          <span>PUBLIC VIEW NOTE</span>
          <span>{networkData.source}</span>
        </div>
        <p>{cluster.notes}</p>
        <p>{networkData.privacy.note}</p>
      </div>
    </div>
  );
}

function HeroNetworkMap({ accent, networkData, selectedId, hoveredId, onSelect, onHover }) {
  const [tick, setTick] = useState(0);
  const reducedMotion = useMemo(function getReducedMotion() {
    return window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
  }, []);

  useEffect(function animate() {
    if (reducedMotion) return undefined;
    let frame = 0;
    let rafId = 0;
    const loop = function animationLoop() {
      frame += 1;
      setTick(frame);
      rafId = requestAnimationFrame(loop);
    };
    rafId = requestAnimationFrame(loop);
    return function cancel() {
      cancelAnimationFrame(rafId);
    };
  }, [reducedMotion]);

  const clusterById = useMemo(function indexClusters() {
    const map = {};
    networkData.clusters.forEach(function mapCluster(cluster) {
      map[cluster.id] = cluster;
    });
    return map;
  }, [networkData.clusters]);

  const highlightedIds = useMemo(function collectHighlighted() {
    const ids = {};
    const activeId = hoveredId || selectedId;
    if (!activeId) return ids;
    ids[activeId] = true;
    networkData.edges.forEach(function markEdge(edge) {
      if (edge.source_id === activeId || edge.target_id === activeId) {
        ids[edge.source_id] = true;
        ids[edge.target_id] = true;
      }
    });
    return ids;
  }, [hoveredId, selectedId, networkData.edges]);

  return (
    <div className="hero-network-map">
      <svg viewBox="0 0 1000 700" preserveAspectRatio="xMidYMid meet" style={{ width: "100%", height: "100%", display: "block" }}>
        <defs>
          <radialGradient id="heroNodeGlow" cx="0.5" cy="0.5" r="0.5">
            <stop offset="0%" stopColor={accent} stopOpacity="0.7" />
            <stop offset="58%" stopColor={accent} stopOpacity="0.18" />
            <stop offset="100%" stopColor={accent} stopOpacity="0" />
          </radialGradient>
        </defs>

        <path d={SG_PATH} fill="rgba(255,92,170,0.05)" stroke="rgba(255,255,255,0.12)" strokeWidth="1" />
        <ellipse cx="370" cy="448" rx="34" ry="6" fill="rgba(255,255,255,0.04)" stroke="rgba(255,255,255,0.08)" />
        <ellipse cx="220" cy="430" rx="40" ry="8" fill="rgba(255,255,255,0.04)" stroke="rgba(255,255,255,0.08)" />
        <ellipse cx="640" cy="248" rx="28" ry="7" fill="rgba(255,255,255,0.04)" stroke="rgba(255,255,255,0.08)" />
        <ellipse cx="700" cy="262" rx="22" ry="6" fill="rgba(255,255,255,0.04)" stroke="rgba(255,255,255,0.08)" />

        {networkData.edges.map(function drawEdge(edge, edgeIndex) {
          const source = clusterById[edge.source_id];
          const target = clusterById[edge.target_id];
          if (!source || !target) return null;
          const active = highlightedIds[source.id] && highlightedIds[target.id];
          const edgeAccent = active ? accent : "rgba(255,255,255,0.1)";
          const packetPhase = reducedMotion ? 0.52 : ((tick * edge.pulse_rate_hz * 0.014) + edgeIndex * 0.11) % 1;
          const packetX = source.x + (target.x - source.x) * packetPhase;
          const packetY = source.y + (target.y - source.y) * packetPhase;

          return (
            <g key={edge.id}>
              <line
                x1={source.x}
                y1={source.y}
                x2={target.x}
                y2={target.y}
                stroke={edgeAccent}
                strokeOpacity={active ? 0.42 : 0.16}
                strokeWidth={active ? 1.1 : 0.8}
              />
              {!reducedMotion ? (
                <circle cx={packetX} cy={packetY} r={1.6 + edge.weight * 0.15} fill={accent} opacity={active ? 0.95 : 0.6} />
              ) : null}
            </g>
          );
        })}

        {networkData.clusters.map(function drawCluster(cluster) {
          const selected = cluster.id === selectedId;
          const hovered = cluster.id === hoveredId;
          const color = statusColor(cluster.status, accent);
          const glowRadius = cluster.r * 2.2 + (selected ? 7 : hovered ? 4 : 0);
          const showLabel = selected || hovered || cluster.activity_index > 88;

          return (
            <g
              key={cluster.id}
              onMouseEnter={function handleEnter() { onHover(cluster.id); }}
              onMouseLeave={function handleLeave() { onHover(null); }}
              onClick={function handleClick() { onSelect(cluster.id); }}
              style={{ cursor: "pointer" }}
            >
              <circle cx={cluster.x} cy={cluster.y} r={glowRadius} fill="url(#heroNodeGlow)" opacity={selected ? 0.95 : 0.62} />
              <circle cx={cluster.x} cy={cluster.y} r={cluster.r + (selected ? 3 : 1.8)} fill="none" stroke={color} strokeOpacity={selected ? 0.72 : 0.35} strokeWidth={selected ? 1.5 : 0.9} />
              <circle cx={cluster.x} cy={cluster.y} r={cluster.r} fill={color} opacity={cluster.status === "idle" ? 0.74 : 1} />
              {showLabel ? (
                <g style={{ fontFamily: "IBM Plex Mono, monospace", fill: "#B6BBC2" }}>
                  <text x={cluster.x + 10} y={cluster.y - 4} fontSize="9">{cluster.label}</text>
                  <text x={cluster.x + 10} y={cluster.y + 8} fontSize="8" fill="#6E757F">
                    {cluster.activity_index}/100 · {cluster.cells_reporting} cells
                  </text>
                </g>
              ) : null}
            </g>
          );
        })}

        <g style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: 9, fill: "#4A5059", letterSpacing: "0.08em" }}>
          <text x="40" y="660">1.290° N</text>
          <text x="40" y="675">103.851° E</text>
          <line x1="900" y1="665" x2="960" y2="665" stroke="#4A5059" strokeWidth="0.7" />
          <text x="900" y="678">10 KM</text>
        </g>
      </svg>
    </div>
  );
}

function Hero({ accent, networkData }) {
  const fallbackNetwork = window.GraphPublicApi && window.GraphPublicApi.getNetwork ? window.GraphPublicApi.getNetwork("sg") : null;
  const snapshot = networkData || fallbackNetwork;
  const [selectedId, setSelectedId] = useState(snapshot ? snapshot.default_selected_id : null);
  const [hoveredId, setHoveredId] = useState(null);

  useEffect(function syncDefaultSelection() {
    if (!snapshot) return;
    setSelectedId(function preserveSelection(previous) {
      const hasPrevious = snapshot.clusters.some(function hasCluster(cluster) {
        return cluster.id === previous;
      });
      return hasPrevious ? previous : snapshot.default_selected_id;
    });
  }, [snapshot]);

  if (!snapshot) return null;

  const selectedCluster = snapshot.clusters.find(function findSelected(cluster) {
    return cluster.id === (hoveredId || selectedId);
  }) || snapshot.clusters[0];

  return (
    <section className="hero" data-screen-label="hero">
      <div className="wrap">
        <div className="hero-grid">
          <div>
            <div className="pill"><span className="dot"></span><span>LIVE · EXTERNAL VIEW · ANONYMISED NETWORK</span></div>
            <h1 className="h1">
              A functional map for <em>distributed energy.</em>
            </h1>
            <p className="lede">
              Graph turns noisy field telemetry into a coherent operating surface. This public preview uses the anonymised external map model only, so you can explore network activity without exposing exact sites or internal portfolio-level statistics.
            </p>
            <div className="hero-ctas">
              <a className="btn btn-primary" href="#developers">Explore the public data model →</a>
              <a className="btn btn-ghost" href="#live">See the live external view</a>
            </div>
            <div className="hero-meta">
              <div className="kv">
                <div className="k mono">ACTIVE CLUSTERS</div>
                <div className="v">{snapshot.summary.active_clusters}</div>
              </div>
              <div className="kv">
                <div className="k mono">OBSERVATION CELLS</div>
                <div className="v">{snapshot.summary.observation_cells}</div>
              </div>
              <div className="kv">
                <div className="k mono">ACTIVITY INDEX</div>
                <div className="v">{snapshot.summary.activity_index}<span style={{ fontSize: 13, color: "var(--ink-3)", fontWeight: 400 }}>/100</span></div>
              </div>
              <div className="kv">
                <div className="k mono">FRESHNESS</div>
                <div className="v">{formatAgo(snapshot.summary.freshness_sec)}</div>
              </div>
            </div>
          </div>

          <div className="hero-canvas">
            <span className="hero-canvas-corner tl"></span>
            <span className="hero-canvas-corner tr"></span>
            <span className="hero-canvas-corner bl"></span>
            <span className="hero-canvas-corner br"></span>
            <div className="hero-canvas-chrome">
              <span>graph.sg/network/public-external</span>
              <span className="right">
                <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
                  <span style={{ width: 6, height: 6, borderRadius: "50%", background: accent, boxShadow: "0 0 8px " + accent }}></span>
                  STREAMING
                </span>
                <span>10M · 1H · EXTERNAL</span>
              </span>
            </div>

            <div className="hero-network-stage">
              <HeroNetworkMap
                accent={accent}
                networkData={snapshot}
                selectedId={selectedId}
                hoveredId={hoveredId}
                onSelect={setSelectedId}
                onHover={setHoveredId}
              />
              <NetworkInspector cluster={selectedCluster} networkData={snapshot} accent={accent} />
            </div>

            <div className="hero-network-footer">
              <span>● solar-heavy · ● battery-present · ◯ ev-present · □ mixed external cells</span>
              <span>{snapshot.summary.signal_events_5m} events / 5m · {snapshot.generated_at.slice(11, 16)} SGT</span>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

window.Hero = Hero;
