/* eslint-disable react/no-unknown-property */
'use client';

import React, { useRef, useMemo, useState, useEffect } from 'react';
import { Canvas, useFrame } from '@react-three/fiber';
import { OrbitControls, PerspectiveCamera, Stars, Line } from '@react-three/drei';
import { EffectComposer, Bloom } from '@react-three/postprocessing';
import * as THREE from 'three';

// ═══════════════════════════════════════════════════════════════
//  CORE ALGORITHMS
// ═══════════════════════════════════════════════════════════════

// Deterministic hash
function sr(seed: number) {
  const x = Math.sin(seed * 127.1 + 311.7) * 43758.5453;
  return x - Math.floor(x);
}

// ── TERRAIN HEIGHT FUNCTION ──
// This is the SINGLE SOURCE OF TRUTH for terrain elevation.
// Used by BOTH the terrain mesh AND all object placement.
const TERRAIN_R = 260;
function terrainY(x: number, z: number): number {
  const dist = Math.sqrt(x * x + z * z);
  const edge = Math.min(1, dist / TERRAIN_R);
  const h = Math.max(0, 1 - edge * 1.3);
  let y = 0;
  y += Math.sin(x * 0.05) * Math.cos(z * 0.04) * 1.3 * h;
  y += Math.sin(x * 0.1 + 2) * Math.cos(z * 0.08 + 1) * 0.5 * h;
  y += Math.sin(x * 0.02 + 5) * Math.cos(z * 0.025 + 3) * 1.0 * h;
  y -= edge * edge * 25;
  return y;
}

// Place on terrain — EVERY object uses this
function onTerrain(x: number, z: number): THREE.Vector3 {
  return new THREE.Vector3(x, terrainY(x, z), z);
}

// ── CATENARY CABLE ──
// Real catenary droop: cosh-based sag between two attachment points
function catenarySag(t: number): number {
  // t: 0→1 along cable. Returns droop factor: 0 at ends, -1 at center
  const u = t * 2 - 1; // -1 → 1
  const cEdge = Math.cosh(2.5);
  return -(cEdge - Math.cosh(u * 2.5)) / (cEdge - 1);
}

function catenaryPoints(
  p1: THREE.Vector3, p2: THREE.Vector3,
  sag: number, segments: number = 20,
): THREE.Vector3[] {
  const pts: THREE.Vector3[] = [];
  for (let i = 0; i <= segments; i++) {
    const t = i / segments;
    pts.push(new THREE.Vector3(
      p1.x + (p2.x - p1.x) * t,
      p1.y + (p2.y - p1.y) * t + catenarySag(t) * sag,
      p1.z + (p2.z - p1.z) * t,
    ));
  }
  return pts;
}

// ── POISSON DISC SAMPLING (approximate) for natural spacing ──
function poissonDisc(
  count: number, radius: number, bounds: number, seed: number,
  exclusions: THREE.Vector3[] = [], exRadius = 12,
): THREE.Vector3[] {
  const pts: THREE.Vector3[] = [];
  const attempts = count * 12;
  for (let i = 0; i < attempts && pts.length < count; i++) {
    const x = (sr(seed + i * 17) - 0.5) * bounds * 2;
    const z = (sr(seed + i * 23 + 1000) - 0.5) * bounds * 2;
    if (Math.sqrt(x * x + z * z) > TERRAIN_R * 0.75) continue;
    if (pts.some(p => Math.hypot(x - p.x, z - p.z) < radius)) continue;
    if (exclusions.some(p => Math.hypot(x - p.x, z - p.z) < exRadius)) continue;
    pts.push(onTerrain(x, z));
  }
  return pts;
}

function nearest(pt: THREE.Vector3, list: THREE.Vector3[]): THREE.Vector3 {
  let best = list[0], bestD = Infinity;
  for (const c of list) { const d = Math.hypot(pt.x - c.x, pt.z - c.z); if (d < bestD) { bestD = d; best = c; } }
  return best;
}

// ═══════════════════════════════════════════════════════════════
//  PROCEDURAL WORLD — all computed from algorithms
// ═══════════════════════════════════════════════════════════════

// Step 1: Place hub substations at fixed strategic positions
const HUBS = [onTerrain(-6, 14), onTerrain(50, -2)];

// Step 2: Place cities at the periphery
const CITY_DATA = [
  { city: onTerrain(100, -55), sub: onTerrain(84, -46) },
  { city: onTerrain(96, 58), sub: onTerrain(82, 50) },
  { city: onTerrain(-4, -102), sub: onTerrain(-3, -86) },
];

// Step 3: Wind farm zones — use noise to find suitable areas
type WindFarm = {
  sub: THREE.Vector3;
  turbines: THREE.Vector3[];
  chains: THREE.Vector3[][]; // turbine→turbine→sub rows
};

function placeWindFarm(
  cx: number, cz: number,
  cols: number, rows: number,
  spacing: number,
  subOffX: number, subOffZ: number,
  rotDeg: number, seed: number,
): WindFarm {
  const rad = (rotDeg * Math.PI) / 180;
  const co = Math.cos(rad), si = Math.sin(rad);
  const grid: THREE.Vector3[][] = [];
  const turbines: THREE.Vector3[] = [];

  for (let r = 0; r < rows; r++) {
    const row: THREE.Vector3[] = [];
    for (let c = 0; c < cols; c++) {
      const lx = (c - (cols - 1) / 2) * spacing + (sr(seed + r * 10 + c) - 0.5) * 2;
      const lz = (r - (rows - 1) / 2) * spacing + (sr(seed + r * 10 + c + 50) - 0.5) * 2;
      const wx = cx + lx * co - lz * si;
      const wz = cz + lx * si + lz * co;
      const pos = onTerrain(wx, wz);
      turbines.push(pos);
      row.push(pos);
    }
    grid.push(row);
  }

  const sub = onTerrain(cx + subOffX, cz + subOffZ);

  // Chain: each row connects turbine→turbine→sub
  const chains: THREE.Vector3[][] = grid.map(row => [...row, sub]);

  return { sub, turbines, chains };
}

const WIND_FARMS: WindFarm[] = [
  placeWindFarm(-82, 62, 3, 2, 14, 32, -10, 5, 101),
  placeWindFarm(16, 90, 3, 2, 13, -22, -16, 12, 201),
  placeWindFarm(-50, -22, 2, 3, 12, 20, 12, -8, 301),
  placeWindFarm(70, 52, 3, 2, 12, -24, -14, 3, 401),
  placeWindFarm(-100, -8, 2, 2, 14, 22, 8, 0, 501),
  placeWindFarm(90, -64, 3, 2, 12, -26, 10, -6, 601),
  placeWindFarm(-60, 92, 2, 2, 13, 18, -16, 18, 701),
  placeWindFarm(44, -84, 2, 3, 12, -18, 20, 0, 801),
];

// Step 4: Solar parks with subs at edge
type SolarPark = { pos: THREE.Vector3; sub: THREE.Vector3; rows: number; cols: number };

const SOLAR_PARKS: SolarPark[] = [
  { pos: onTerrain(-114, -56), sub: onTerrain(-98, -48), rows: 6, cols: 8 },
  { pos: onTerrain(-104, -72), sub: onTerrain(-98, -48), rows: 5, cols: 7 },
  { pos: onTerrain(100, 18), sub: onTerrain(88, 12), rows: 5, cols: 7 },
  { pos: onTerrain(-48, -70), sub: onTerrain(-40, -58), rows: 4, cols: 6 },
  { pos: onTerrain(58, -20), sub: onTerrain(52, -14), rows: 5, cols: 6 },
  { pos: onTerrain(-84, 34), sub: onTerrain(-74, 30), rows: 4, cols: 5 },
];

// Deduplicated solar subs
const solarSubSet = new Set<string>();
const SOLAR_SUBS: THREE.Vector3[] = [];
SOLAR_PARKS.forEach(sp => {
  const k = `${sp.sub.x.toFixed(1)},${sp.sub.z.toFixed(1)}`;
  if (!solarSubSet.has(k)) { solarSubSet.add(k); SOLAR_SUBS.push(sp.sub); }
});

// Step 5: Collect all gen subs and auto-route to hubs
const ALL_GEN_SUBS = [...WIND_FARMS.map(f => f.sub), ...SOLAR_SUBS];
const ALL_CITY_SUBS = CITY_DATA.map(c => c.sub);
const ALL_SUBS = [...ALL_GEN_SUBS, ...HUBS, ...ALL_CITY_SUBS];

// Step 6: HSVL tower routes
const TWR_H = 9;
function lerpRoute(from: THREE.Vector3, to: THREE.Vector3, n: number): THREE.Vector3[] {
  const pts = [from];
  for (let i = 1; i <= n; i++) {
    const t = i / (n + 1);
    pts.push(onTerrain(from.x + (to.x - from.x) * t, from.z + (to.z - from.z) * t));
  }
  pts.push(to);
  return pts;
}
function autoTowerCount(a: THREE.Vector3, b: THREE.Vector3) {
  return Math.max(2, Math.floor(Math.hypot(a.x - b.x, a.z - b.z) / 22));
}

const HSVL_ROUTES: THREE.Vector3[][] = [];
ALL_GEN_SUBS.forEach(sub => {
  const hub = nearest(sub, HUBS);
  HSVL_ROUTES.push(lerpRoute(sub, hub, autoTowerCount(sub, hub)));
});
HSVL_ROUTES.push(lerpRoute(HUBS[0], HUBS[1], autoTowerCount(HUBS[0], HUBS[1])));
CITY_DATA.forEach(cd => {
  const hub = nearest(cd.sub, HUBS);
  HSVL_ROUTES.push(lerpRoute(hub, cd.sub, autoTowerCount(hub, cd.sub)));
});

// Step 7: All cable pairs
const DIST_CABLES: [THREE.Vector3, THREE.Vector3][] = [
  ...SOLAR_PARKS.map(sp => [sp.pos, sp.sub] as [THREE.Vector3, THREE.Vector3]),
  ...CITY_DATA.map(cd => [cd.sub, cd.city] as [THREE.Vector3, THREE.Vector3]),
];

// Step 8: All infra for exclusion
const ALL_INFRA: THREE.Vector3[] = [
  ...ALL_SUBS,
  ...CITY_DATA.map(c => c.city),
  ...WIND_FARMS.flatMap(f => f.turbines),
  ...SOLAR_PARKS.map(s => s.pos),
];

// Step 9: Poisson-disc distributed forests
const FOREST_POSITIONS = poissonDisc(55, 18, 140, 5000, ALL_INFRA, 14);

// ═══════════════════════════════════════════════════════════════
//  TERRAIN MESH — uses the same terrainY() function
// ═══════════════════════════════════════════════════════════════
const Terrain = () => {
  const geometry = useMemo(() => {
    const geo = new THREE.CircleGeometry(TERRAIN_R, 200);
    const pos = geo.attributes.position;
    for (let i = 0; i < pos.count; i++) {
      const x = pos.getX(i);
      const z = -pos.getY(i);
      pos.setX(i, x);
      pos.setY(i, terrainY(x, z));
      pos.setZ(i, z);
    }
    geo.computeVertexNormals();
    return geo;
  }, []);
  return (
    <group>
      <mesh geometry={geometry}><meshStandardMaterial color="#020a16" roughness={0.95} metalness={0.05} /></mesh>
      <mesh geometry={geometry} position={[0, 0.05, 0]}><meshBasicMaterial color="#0a2a50" wireframe transparent opacity={0.15} /></mesh>
    </group>
  );
};

// ═══════════════════════════════════════════════════════════════
//  COMPONENTS
// ═══════════════════════════════════════════════════════════════

const SolarField = ({ position, rows = 5, cols = 7 }: { position: THREE.Vector3; rows?: number; cols?: number }) => (
  <group position={position}>
    {Array.from({ length: rows }).map((_, r) =>
      Array.from({ length: cols }).map((_, c) => (
        <group key={`${r}-${c}`} position={[c * 2.2 - (cols * 2.2) / 2, 0, r * 2 - (rows * 2) / 2]}>
          <mesh position={[0, 0.35, 0]}><cylinderGeometry args={[0.02, 0.02, 0.7, 3]} /><meshBasicMaterial color="#1a4a70" transparent opacity={0.3} /></mesh>
          <group position={[0, 0.7, 0]} rotation={[-Math.PI / 5, 0, 0]}>
            <mesh><boxGeometry args={[1.8, 1.1, 0.04]} /><meshStandardMaterial color="#0a1e3d" emissive="#002244" emissiveIntensity={0.3} metalness={0.9} roughness={0.1} /></mesh>
            <mesh position={[0, 0, 0.025]}><boxGeometry args={[1.8, 1.1, 0.01]} /><meshBasicMaterial color="#3388cc" wireframe transparent opacity={0.15} toneMapped={false} /></mesh>
          </group>
        </group>
      ))
    )}
  </group>
);

const TH = 6, BLade = 3;
const WindTurbine = ({ position, seed = 0 }: { position: THREE.Vector3; seed?: number }) => {
  const bladesRef = useRef<THREE.Group>(null);
  const speed = 1.8 + sr(seed * 7) * 1.2;
  useFrame((s) => { if (bladesRef.current) bladesRef.current.rotation.z = s.clock.elapsedTime * speed; });
  return (
    <group position={position}>
      <mesh position={[0, TH / 2, 0]}><cylinderGeometry args={[0.07, 0.14, TH, 6]} /><meshBasicMaterial color="#4488cc" transparent opacity={0.55} toneMapped={false} /></mesh>
      <mesh position={[0, TH, -0.15]}><boxGeometry args={[0.2, 0.18, 0.4]} /><meshBasicMaterial color="#5599dd" transparent opacity={0.55} toneMapped={false} /></mesh>
      <group position={[0, TH, 0.08]} ref={bladesRef}>
        <mesh><sphereGeometry args={[0.1, 6, 6]} /><meshBasicMaterial color="#80ccff" toneMapped={false} /></mesh>
        {[0, 1, 2].map(i => (
          <group key={i} rotation={[0, 0, (i * Math.PI * 2) / 3]}>
            <mesh position={[0, BLade / 2 + 0.1, 0]}><boxGeometry args={[0.12, BLade, 0.02]} /><meshBasicMaterial color="#70ccff" transparent opacity={0.45} toneMapped={false} /></mesh>
          </group>
        ))}
      </group>
    </group>
  );
};

const Substation = ({ position, size = 'small' }: { position: THREE.Vector3; size?: 'small' | 'large' }) => {
  const s = size === 'large' ? 1.3 : 0.8;
  const pulseRef = useRef<THREE.Mesh>(null);
  useFrame((st) => { if (pulseRef.current) pulseRef.current.scale.setScalar(1 + Math.sin(st.clock.elapsedTime * 2.5) * 0.15); });
  return (
    <group position={position}>
      <mesh position={[0, 0.8 * s, 0]}><boxGeometry args={[4 * s, 1.6 * s, 3 * s]} /><meshBasicMaterial color="#3388aa" wireframe transparent opacity={0.2} toneMapped={false} /></mesh>
      <mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, 0.05, 0]}><planeGeometry args={[4 * s, 3 * s]} /><meshStandardMaterial color="#0a1825" roughness={0.9} metalness={0.1} /></mesh>
      {[[-0.8 * s, -0.5 * s], [0.8 * s, -0.5 * s], [0, 0.6 * s]].map(([x, z], i) => (
        <group key={i} position={[x, 0, z]}>
          <mesh position={[0, 0.5 * s, 0]}><boxGeometry args={[0.8 * s, 1 * s, 0.6 * s]} /><meshStandardMaterial color="#0c1e35" emissive="#0a1828" emissiveIntensity={0.3} metalness={0.6} roughness={0.4} /></mesh>
          <mesh position={[0, 0.5 * s, 0]}><boxGeometry args={[0.85 * s, 1.05 * s, 0.65 * s]} /><meshBasicMaterial color="#4488aa" wireframe transparent opacity={0.15} toneMapped={false} /></mesh>
          <mesh position={[0, 1.1 * s, 0]}><cylinderGeometry args={[0.04 * s, 0.06 * s, 0.3 * s, 4]} /><meshBasicMaterial color="#77ccee" transparent opacity={0.5} toneMapped={false} /></mesh>
        </group>
      ))}
      <mesh position={[0, 1.2 * s, -0.5 * s]} rotation={[0, 0, Math.PI / 2]}><cylinderGeometry args={[0.03, 0.03, 2.5 * s, 3]} /><meshBasicMaterial color="#60eeaa" transparent opacity={0.4} toneMapped={false} /></mesh>
      <mesh position={[0, 1.6 * s, 0]} ref={pulseRef}><sphereGeometry args={[0.2 * s, 8, 8]} /><meshBasicMaterial color="#60ff90" toneMapped={false} /></mesh>
    </group>
  );
};

const City = ({ position, seed = 0 }: { position: THREE.Vector3; seed?: number }) => {
  const buildings = useMemo(() => {
    const items = [];
    const count = 10 + Math.floor(sr(seed * 3) * 8);
    for (let i = 0; i < count; i++) {
      const angle = sr(seed * 100 + i * 17) * Math.PI * 2;
      const radius = 0.5 + sr(seed * 100 + i * 29) * 6;
      const height = 1 + sr(seed * 100 + i * 37) * 4;
      items.push({
        x: Math.cos(angle) * radius, z: Math.sin(angle) * radius,
        height, width: 0.4 + sr(seed * 100 + i * 43) * 0.8,
        depth: 0.4 + sr(seed * 100 + i * 47) * 0.6,
        rows: Math.max(1, Math.floor(height / 0.8)),
      });
    }
    return items;
  }, [seed]);

  return (
    <group position={position}>
      {buildings.map((b, i) => (
        <group key={i} position={[b.x, 0, b.z]}>
          <mesh position={[0, b.height / 2, 0]}><boxGeometry args={[b.width, b.height, b.depth]} /><meshStandardMaterial color="#040810" emissive="#081530" emissiveIntensity={0.15} metalness={0.9} roughness={0.1} /></mesh>
          {Array.from({ length: b.rows }).map((_, row) => {
            const wc = Math.max(1, Math.floor(b.width / 0.35));
            return Array.from({ length: wc }).map((_, col) => {
              if (sr(seed * 1000 + i * 100 + row * 10 + col) < 0.25) return null;
              const color = sr(seed * 2000 + i * 50 + row + col) > 0.45 ? '#ffdd44' : '#aaddff';
              const xP = wc > 1 ? (col / (wc - 1) - 0.5) * (b.width * 0.7) : 0;
              return (
                <group key={`w-${row}-${col}`}>
                  <mesh position={[xP, 0.35 + row * 0.8, b.depth / 2 + 0.01]}><planeGeometry args={[0.22, 0.28]} /><meshBasicMaterial color={color} toneMapped={false} /></mesh>
                  <mesh position={[xP, 0.35 + row * 0.8, -b.depth / 2 - 0.01]} rotation={[0, Math.PI, 0]}><planeGeometry args={[0.22, 0.28]} /><meshBasicMaterial color={color} toneMapped={false} /></mesh>
                </group>
              );
            });
          })}
          <mesh position={[0, b.height + 0.08, 0]}><sphereGeometry args={[0.05, 4, 4]} /><meshBasicMaterial color="#ff4444" toneMapped={false} /></mesh>
        </group>
      ))}
      <pointLight position={[0, 5, 0]} intensity={8} color="#ffaa44" distance={80} />
    </group>
  );
};

// ═══════════════════════════════════════════════════════════════
//  HOCHSPANNUNGSMAST — tapered pylon
// ═══════════════════════════════════════════════════════════════
const TransmissionTower = ({ position }: { position: THREE.Vector3 }) => (
  <group position={position}>
    <mesh position={[0, TWR_H / 2, 0]}><cylinderGeometry args={[0.15, 0.6, TWR_H, 4]} /><meshBasicMaterial color="#5599bb" transparent opacity={0.5} toneMapped={false} /></mesh>
    <mesh position={[0, TWR_H / 2, 0]}><cylinderGeometry args={[0.18, 0.65, TWR_H, 4]} /><meshBasicMaterial color="#4488aa" wireframe transparent opacity={0.2} toneMapped={false} /></mesh>
    <mesh position={[0, TWR_H, 0]} rotation={[0, 0, Math.PI / 2]}><cylinderGeometry args={[0.04, 0.04, 3.5, 4]} /><meshBasicMaterial color="#6699cc" transparent opacity={0.55} toneMapped={false} /></mesh>
    <mesh position={[0, TWR_H * 0.7, 0]} rotation={[0, 0, Math.PI / 2]}><cylinderGeometry args={[0.03, 0.03, 2.5, 4]} /><meshBasicMaterial color="#5588aa" transparent opacity={0.4} toneMapped={false} /></mesh>
    {[-1.6, 1.6].map((xOff, i) => (
      <mesh key={i} position={[xOff, TWR_H - 0.3, 0]}><cylinderGeometry args={[0.02, 0.04, 0.4, 4]} /><meshBasicMaterial color="#88ccee" transparent opacity={0.5} toneMapped={false} /></mesh>
    ))}
    <mesh position={[0, TWR_H + 0.3, 0]}><sphereGeometry args={[0.1, 6, 6]} /><meshBasicMaterial color="#ff4444" toneMapped={false} /></mesh>
  </group>
);

// ═══════════════════════════════════════════════════════════════
//  CABLE NETWORK — all use catenary algorithm
// ═══════════════════════════════════════════════════════════════
const CableNetwork = () => {
  // Pre-compute all cable point arrays
  const cables = useMemo(() => {
    const result: { points: THREE.Vector3[]; color: string; width: number; opacity: number }[] = [];

    // HSVL cables: tower-top to tower-top with catenary sag
    HSVL_ROUTES.forEach(route => {
      for (let i = 1; i < route.length; i++) {
        const a = route[i - 1].clone(); a.y += TWR_H;
        const b = route[i].clone(); b.y += TWR_H;
        result.push({
          points: catenaryPoints(a, b, 2.5, 20),
          color: '#6699cc', width: 1.5, opacity: 0.4,
        });
      }
    });

    // Distribution cables: solar→sub, sub→city (elevated)
    DIST_CABLES.forEach(([from, to]) => {
      const a = from.clone(); a.y += 5;
      const b = to.clone(); b.y += 5;
      result.push({
        points: catenaryPoints(a, b, 1.5, 16),
        color: '#55cc88', width: 1.2, opacity: 0.35,
      });
    });

    // Wind farm internal chains: ground-level cables
    WIND_FARMS.forEach(farm => {
      farm.chains.forEach(chain => {
        for (let i = 1; i < chain.length; i++) {
          const a = chain[i - 1].clone(); a.y += 0.3;
          const b = chain[i].clone(); b.y += 0.3;
          result.push({
            points: catenaryPoints(a, b, 0.3, 8),
            color: '#30ff70', width: 1, opacity: 0.2,
          });
        }
      });
    });

    return result;
  }, []);

  // Towers at intermediate route points
  const towers = useMemo(() => {
    const pts: THREE.Vector3[] = [];
    HSVL_ROUTES.forEach(route => {
      for (let i = 1; i < route.length - 1; i++) pts.push(route[i]);
    });
    return pts;
  }, []);

  return (
    <group>
      {towers.map((pos, i) => <TransmissionTower key={`t-${i}`} position={pos} />)}
      {cables.map((c, i) => (
        <Line key={`c-${i}`} points={c.points} color={c.color} lineWidth={c.width} transparent opacity={c.opacity} />
      ))}
    </group>
  );
};

// ═══════════════════════════════════════════════════════════════
//  FOREST — Poisson-disc distributed, terrain-aware
// ═══════════════════════════════════════════════════════════════
const Forest = ({ position, seed = 0, count = 30 }: { position: THREE.Vector3; seed?: number; count?: number }) => {
  const trees = useMemo(() => {
    const items = [];
    for (let i = 0; i < count; i++) {
      // Use noise for natural clumping
      const angle = sr(seed * 200 + i * 11) * Math.PI * 2;
      const radius = sr(seed * 200 + i * 23) * 14;
      const wx = position.x + Math.cos(angle) * radius;
      const wz = position.z + Math.sin(angle) * radius;
      // Skip if near infrastructure
      if (ALL_INFRA.some(p => Math.hypot(wx - p.x, wz - p.z) < 10)) continue;
      // Skip if too far from terrain center
      if (Math.sqrt(wx * wx + wz * wz) > TERRAIN_R * 0.72) continue;

      const localY = terrainY(wx, wz) - position.y; // height relative to parent group
      const trunkH = 0.4 + sr(seed * 200 + i * 31) * 1;
      const canopyH = 0.6 + sr(seed * 200 + i * 37) * 1.5;
      const canopyR = 0.2 + sr(seed * 200 + i * 43) * 0.4;
      const shade = sr(seed * 200 + i * 47);
      items.push({
        x: Math.cos(angle) * radius, y: localY, z: Math.sin(angle) * radius,
        trunkH, canopyH, canopyR, shade,
        brightness: 0.2 + sr(seed * 200 + i * 41) * 0.3,
      });
    }
    return items;
  }, [seed, count, position]);

  return (
    <group position={position}>
      {trees.map((t, i) => (
        <group key={i} position={[t.x, t.y, t.z]}>
          <mesh position={[0, t.trunkH / 2, 0]}><cylinderGeometry args={[0.03, 0.06, t.trunkH, 4]} /><meshBasicMaterial color="#1a3328" transparent opacity={0.6} /></mesh>
          <mesh position={[0, t.trunkH + t.canopyH / 2, 0]}><coneGeometry args={[t.canopyR, t.canopyH, 5]} /><meshBasicMaterial color={t.shade > 0.6 ? '#15aa45' : t.shade > 0.3 ? '#1a9050' : '#10804a'} transparent opacity={t.brightness} toneMapped={false} /></mesh>
          <mesh position={[0, t.trunkH + t.canopyH * 0.65, 0]}><coneGeometry args={[t.canopyR * 0.6, t.canopyH * 0.5, 5]} /><meshBasicMaterial color={t.shade > 0.5 ? '#20cc55' : '#18bb50'} transparent opacity={t.brightness * 0.7} toneMapped={false} /></mesh>
        </group>
      ))}
    </group>
  );
};

// ═══════════════════════════════════════════════════════════════
//  ENERGY PARTICLES — flow along catenary cables
// ═══════════════════════════════════════════════════════════════
const EnergyParticles = () => {
  const meshRef = useRef<THREE.InstancedMesh>(null);
  const dummy = useMemo(() => new THREE.Object3D(), []);

  // Build all curves from cable segments for particle paths
  const curves = useMemo(() => {
    const all: THREE.CatmullRomCurve3[] = [];
    // HSVL
    HSVL_ROUTES.forEach(route => {
      for (let i = 1; i < route.length; i++) {
        const a = route[i - 1].clone(); a.y += TWR_H;
        const b = route[i].clone(); b.y += TWR_H;
        all.push(new THREE.CatmullRomCurve3(catenaryPoints(a, b, 2.5, 12)));
      }
    });
    // Distribution
    DIST_CABLES.forEach(([from, to]) => {
      const a = from.clone(); a.y += 5;
      const b = to.clone(); b.y += 5;
      all.push(new THREE.CatmullRomCurve3(catenaryPoints(a, b, 1.5, 10)));
    });
    // Farm chains
    WIND_FARMS.forEach(farm => {
      farm.chains.forEach(chain => {
        for (let i = 1; i < chain.length; i++) {
          const a = chain[i - 1].clone(); a.y += 0.3;
          const b = chain[i].clone(); b.y += 0.3;
          all.push(new THREE.CatmullRomCurve3(catenaryPoints(a, b, 0.3, 6)));
        }
      });
    });
    return all;
  }, []);

  const perCurve = 4;
  const total = curves.length * perCurve;
  const data = useMemo(() => {
    const items = [];
    for (let c = 0; c < curves.length; c++)
      for (let p = 0; p < perCurve; p++)
        items.push({ curve: c, t: p / perCurve, speed: 0.3 + sr(c * 100 + p * 7) * 0.35, phase: sr(c * 100 + p * 13) * Math.PI * 2 });
    return items;
  }, [curves]);

  useFrame((state, delta) => {
    if (!meshRef.current) return;
    data.forEach((d, i) => {
      d.t += delta * d.speed; if (d.t > 1) d.t -= 1;
      const p = curves[d.curve].getPointAt(d.t);
      dummy.position.copy(p);
      dummy.scale.setScalar(0.5 + Math.sin(state.clock.elapsedTime * 6 + d.phase) * 0.3);
      dummy.updateMatrix();
      meshRef.current!.setMatrixAt(i, dummy.matrix);
    });
    meshRef.current.instanceMatrix.needsUpdate = true;
  });

  return (
    <instancedMesh ref={meshRef} args={[undefined, undefined, total]}>
      <sphereGeometry args={[0.18, 8, 8]} />
      <meshBasicMaterial color="#80ffbb" toneMapped={false} />
    </instancedMesh>
  );
};

// ═══════════════════════════════════════════════════════════════
//  AMBIENT MOTES
// ═══════════════════════════════════════════════════════════════
const AmbientMotes = () => {
  const meshRef = useRef<THREE.InstancedMesh>(null);
  const count = 250;
  const dummy = useMemo(() => new THREE.Object3D(), []);
  const motes = useMemo(() => Array.from({ length: count }, (_, i) => ({
    x: (sr(i * 7 + 1) - 0.5) * 220, y: 3 + sr(i * 13 + 2) * 18, z: (sr(i * 19 + 3) - 0.5) * 220,
    speed: 0.1 + sr(i * 23 + 4) * 0.3, phase: sr(i * 29 + 5) * Math.PI * 2,
  })), []);

  useFrame((state) => {
    if (!meshRef.current) return;
    motes.forEach((m, i) => {
      dummy.position.set(m.x + Math.sin(state.clock.elapsedTime * m.speed + m.phase) * 3, m.y + Math.sin(state.clock.elapsedTime * m.speed * 0.7 + m.phase) * 2, m.z + Math.cos(state.clock.elapsedTime * m.speed + m.phase) * 3);
      dummy.scale.setScalar(0.3 + Math.sin(state.clock.elapsedTime * 2 + m.phase) * 0.2);
      dummy.updateMatrix(); meshRef.current!.setMatrixAt(i, dummy.matrix);
    });
    meshRef.current.instanceMatrix.needsUpdate = true;
  });

  return (
    <instancedMesh ref={meshRef} args={[undefined, undefined, count]}>
      <sphereGeometry args={[0.06, 5, 5]} /><meshBasicMaterial color="#50ffa0" transparent opacity={0.35} toneMapped={false} />
    </instancedMesh>
  );
};

// ═══════════════════════════════════════════════════════════════
//  SCENE
// ═══════════════════════════════════════════════════════════════
const Scene = () => (
  <>
    <PerspectiveCamera makeDefault position={[0, 80, 130]} fov={50} />
    <OrbitControls enableZoom={false} enablePan={false} autoRotate autoRotateSpeed={0.3} maxPolarAngle={Math.PI / 2.1} minPolarAngle={Math.PI / 6} />
    <ambientLight intensity={0.3} />
    <directionalLight position={[50, 80, 40]} intensity={1.5} color="#aaddff" />
    <pointLight position={[-60, 40, -40]} intensity={2} color="#40ff80" distance={150} />
    <pointLight position={[60, 30, 50]} intensity={1.5} color="#2060ff" distance={130} />
    <Stars radius={250} depth={100} count={18000} factor={5} saturation={0} fade speed={0.3} />
    <fog attach="fog" args={['#020e1e', 50, 180]} />

    <Terrain />

    {/* Solar parks */}
    {SOLAR_PARKS.map((sp, i) => <SolarField key={`sp-${i}`} position={sp.pos} rows={sp.rows} cols={sp.cols} />)}

    {/* Wind farms */}
    {WIND_FARMS.flatMap((farm, fi) =>
      farm.turbines.map((pos, ti) => <WindTurbine key={`wt-${fi}-${ti}`} position={pos} seed={fi * 100 + ti} />)
    )}

    {/* Substations */}
    {WIND_FARMS.map((f, i) => <Substation key={`ws-${i}`} position={f.sub} size="small" />)}
    {SOLAR_SUBS.map((s, i) => <Substation key={`ss-${i}`} position={s} size="small" />)}
    {HUBS.map((h, i) => <Substation key={`hub-${i}`} position={h} size="large" />)}
    {CITY_DATA.map((cd, i) => <Substation key={`cs-${i}`} position={cd.sub} size="small" />)}

    {/* Cities */}
    {CITY_DATA.map((cd, i) => <City key={`city-${i}`} position={cd.city} seed={i + 1} />)}

    {/* All cables with catenary physics */}
    <CableNetwork />

    {/* Forests — Poisson-disc placed */}
    {FOREST_POSITIONS.map((pos, i) => (
      <Forest key={`f-${i}`} position={pos} seed={i + 1} count={20 + Math.floor(sr(i * 61 + 700) * 25)} />
    ))}

    {/* Energy flow */}
    <EnergyParticles />
    <AmbientMotes />

    <EffectComposer>
      <Bloom luminanceThreshold={0.2} mipmapBlur intensity={3} luminanceSmoothing={0.8} />
    </EffectComposer>
  </>
);

// ═══════════════════════════════════════════════════════════════
export default function HeroIllustration() {
  const [mounted, setMounted] = useState(false);
  useEffect(() => { setMounted(true); }, []); // eslint-disable-line react-hooks/set-state-in-effect
  if (!mounted) return null;
  return (
    <div className="absolute inset-0 z-0 bg-gradient-to-b from-[#010810] via-[#05162e] to-[#0a2a50] w-full h-full cursor-grab active:cursor-grabbing">
      <Canvas gl={{ antialias: true, alpha: false, powerPreference: 'high-performance' }}>
        <Scene />
      </Canvas>
      <div className="absolute inset-0 pointer-events-none bg-[radial-gradient(ellipse_at_center,transparent_30%,#002b49_120%)]" />
    </div>
  );
}
