"use client";

import { useEffect, useRef } from "react";
import * as THREE from "three";

export type TopicPrepVariant = "indie" | "aiagent";

type Props = {
  variant: TopicPrepVariant;
};

function disposeObject3D(root: THREE.Object3D) {
  const materials = new Set<THREE.Material>();
  const geometries = new Set<THREE.BufferGeometry>();
  root.traverse((object) => {
    if (object instanceof THREE.Mesh || object instanceof THREE.LineSegments) {
      const g = object.geometry;
      if (g && !geometries.has(g)) {
        geometries.add(g);
        g.dispose();
      }
      const mat = object.material;
      if (Array.isArray(mat)) mat.forEach((m) => materials.add(m));
      else if (mat) materials.add(mat);
    }
  });
  materials.forEach((m) => m.dispose());
}

/** 独立开发：居家书桌 + 显示器 + homelab 机架 */
function buildIndieDeskScene(root: THREE.Group) {
  const wood = new THREE.MeshStandardMaterial({
    color: 0x6b5344,
    roughness: 0.88,
    metalness: 0.05,
  });
  const deskDark = new THREE.MeshStandardMaterial({
    color: 0x18181b,
    roughness: 0.55,
    metalness: 0.25,
  });
  const screenGlow = new THREE.MeshStandardMaterial({
    color: 0x052e16,
    emissive: 0x4ade80,
    emissiveIntensity: 0.55,
    roughness: 0.35,
  });
  const keyCap = new THREE.MeshStandardMaterial({
    color: 0x3f3f46,
    roughness: 0.45,
    metalness: 0.15,
  });
  const rackLed = new THREE.MeshStandardMaterial({
    color: 0x0c0a09,
    emissive: 0xf59e0b,
    emissiveIntensity: 0.5,
    roughness: 0.4,
  });

  const floor = new THREE.Mesh(new THREE.PlaneGeometry(7, 5.5), wood);
  floor.rotation.x = -Math.PI / 2;
  floor.position.y = -1.15;
  root.add(floor);

  const rug = new THREE.Mesh(new THREE.PlaneGeometry(2.8, 2), new THREE.MeshStandardMaterial({
    color: 0x3d3832,
    roughness: 0.95,
  }));
  rug.rotation.x = -Math.PI / 2;
  rug.position.set(0, -1.14, 0.1);
  root.add(rug);

  const deskTop = new THREE.Mesh(new THREE.BoxGeometry(2.4, 0.07, 1), deskDark);
  deskTop.position.set(0, -0.38, 0.15);
  root.add(deskTop);

  const legGeo = new THREE.BoxGeometry(0.08, 0.45, 0.08);
  const legPositions: [number, number, number][] = [
    [-1, -0.65, -0.25],
    [1, -0.65, -0.25],
    [-1, -0.65, 0.55],
    [1, -0.65, 0.55],
  ];
  for (const [x, y, z] of legPositions) {
    const leg = new THREE.Mesh(legGeo, deskDark);
    leg.position.set(x, y, z);
    root.add(leg);
  }

  const monitorBezel = new THREE.Mesh(new THREE.BoxGeometry(1, 0.62, 0.045), deskDark);
  monitorBezel.position.set(0, 0.12, -0.28);
  root.add(monitorBezel);

  const screen = new THREE.Mesh(new THREE.PlaneGeometry(0.88, 0.52), screenGlow);
  screen.position.set(0, 0.12, -0.28 + 0.023);
  root.add(screen);

  const stand = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.12, 0.15), deskDark);
  stand.position.set(0, -0.28, -0.22);
  root.add(stand);

  const keyboard = new THREE.Mesh(new THREE.BoxGeometry(0.75, 0.035, 0.3), keyCap);
  keyboard.position.set(0, -0.32, 0.38);
  keyboard.rotation.x = -0.06;
  root.add(keyboard);

  const mug = new THREE.Mesh(
    new THREE.CylinderGeometry(0.09, 0.08, 0.12, 16),
    new THREE.MeshStandardMaterial({ color: 0x3f3f46, roughness: 0.4 }),
  );
  mug.position.set(-0.85, -0.31, 0.42);
  root.add(mug);

  const rack = new THREE.Mesh(new THREE.BoxGeometry(0.38, 0.95, 0.42), deskDark);
  rack.position.set(1.05, 0.1, -0.05);
  root.add(rack);

  const rackFace = new THREE.Mesh(new THREE.PlaneGeometry(0.3, 0.82), rackLed);
  rackFace.position.set(1.05 + 0.191, 0.1, -0.05);
  root.add(rackFace);

  for (let row = 0; row < 4; row++) {
    const led = new THREE.Mesh(
      new THREE.PlaneGeometry(0.22, 0.04),
      new THREE.MeshStandardMaterial({
        color: 0x000000,
        emissive: row % 2 === 0 ? 0x22c55e : 0xf59e0b,
        emissiveIntensity: 0.65,
      }),
    );
    led.position.set(1.05 + 0.192, 0.35 - row * 0.18, -0.05);
    root.add(led);
  }

  const miniServer = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.15, 0.18), deskDark);
  miniServer.position.set(1.05, -0.28, 0.45);
  root.add(miniServer);
}

/** AI Agent：赛博空间网格 + 机器人 + 霓虹光环 */
function buildAiCyberScene(root: THREE.Group) {
  const grid = new THREE.GridHelper(9, 28, 0x6366f1, 0x312e81);
  grid.position.y = -1.05;
  const gMat = grid.material;
  if (Array.isArray(gMat)) {
    gMat.forEach((m) => {
      if ("opacity" in m) {
        (m as THREE.Material & { opacity: number }).opacity = 0.45;
        m.transparent = true;
      }
    });
  } else if (gMat && "opacity" in gMat) {
    (gMat as THREE.Material & { opacity: number }).opacity = 0.45;
    gMat.transparent = true;
  }
  root.add(grid);

  const bodyMat = new THREE.MeshStandardMaterial({
    color: 0x52525b,
    metalness: 0.55,
    roughness: 0.28,
    flatShading: true,
  });
  const glowCyan = new THREE.MeshStandardMaterial({
    color: 0x06b6d4,
    emissive: 0x22d3ee,
    emissiveIntensity: 0.85,
  });
  const glowMagenta = new THREE.MeshStandardMaterial({
    color: 0xd946ef,
    emissive: 0xc026d3,
    emissiveIntensity: 0.55,
  });

  const robot = new THREE.Group();
  robot.position.y = -0.15;

  const torso = new THREE.Mesh(new THREE.BoxGeometry(0.52, 0.58, 0.32), bodyMat);
  torso.position.y = 0.1;
  robot.add(torso);

  const chestPanel = new THREE.Mesh(new THREE.PlaneGeometry(0.35, 0.25), glowCyan);
  chestPanel.position.set(0, 0.12, 0.161);
  robot.add(chestPanel);

  const head = new THREE.Mesh(new THREE.BoxGeometry(0.44, 0.36, 0.38), bodyMat);
  head.position.y = 0.55;
  robot.add(head);

  const visor = new THREE.Mesh(new THREE.BoxGeometry(0.38, 0.12, 0.02), glowCyan);
  visor.position.set(0, 0.52, 0.19);
  robot.add(visor);

  const eyeL = new THREE.Mesh(new THREE.SphereGeometry(0.055, 16, 16), glowCyan);
  eyeL.position.set(-0.1, 0.56, 0.18);
  const eyeR = new THREE.Mesh(new THREE.SphereGeometry(0.055, 16, 16), glowCyan);
  eyeR.position.set(0.1, 0.56, 0.18);
  robot.add(eyeL, eyeR);

  const antenna = new THREE.Mesh(new THREE.CylinderGeometry(0.025, 0.03, 0.28, 8), glowMagenta);
  antenna.position.set(0, 0.82, 0);
  robot.add(antenna);

  const armL = new THREE.Mesh(new THREE.BoxGeometry(0.12, 0.45, 0.12), bodyMat);
  armL.position.set(-0.38, 0.05, 0);
  const armR = armL.clone();
  armR.position.x = 0.38;
  robot.add(armL, armR);

  root.add(robot);

  for (let i = 0; i < 3; i++) {
    const ringMat = new THREE.MeshBasicMaterial({
      color: i === 1 ? 0xa855f7 : 0x22d3ee,
      transparent: true,
      opacity: 0.35 - i * 0.08,
    });
    const ring = new THREE.Mesh(new THREE.TorusGeometry(0.95 + i * 0.22, 0.012, 8, 64), ringMat);
    ring.rotation.x = Math.PI / 2;
    ring.position.y = -0.85 + i * 0.15;
    root.add(ring);
  }

  const holo = new THREE.Mesh(
    new THREE.OctahedronGeometry(0.18, 0),
    new THREE.MeshBasicMaterial({ color: 0x67e8f9, wireframe: true, transparent: true, opacity: 0.5 }),
  );
  holo.position.set(-0.55, 0.35, 0.35);
  root.add(holo);

  return { robot, holo };
}

export function TopicPrepThreeScene({ variant }: Props) {
  const containerRef = useRef<HTMLDivElement>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    const container = containerRef.current;
    if (!canvas || !container) return;

    const renderer = new THREE.WebGLRenderer({
      canvas,
      antialias: true,
      alpha: true,
      powerPreference: "high-performance",
    });

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(42, 1, 0.1, 100);
    camera.position.set(0, 0.35, 5.2);

    const group = new THREE.Group();
    scene.add(group);

    let bobRefs: { robot?: THREE.Group; holo?: THREE.Mesh } | null = null;

    if (variant === "indie") {
      scene.background = null;
      const ambient = new THREE.AmbientLight(0xfff5e6, 0.45);
      scene.add(ambient);
      const warm = new THREE.PointLight(0xffb86b, 1.1, 12);
      warm.position.set(0.6, 1.2, 1.2);
      scene.add(warm);
      const cool = new THREE.PointLight(0x4ade80, 0.35, 8);
      cool.position.set(-0.3, 0.5, 0.5);
      scene.add(cool);
      const dir = new THREE.DirectionalLight(0xffffff, 0.35);
      dir.position.set(-2, 4, 3);
      scene.add(dir);

      buildIndieDeskScene(group);
      group.rotation.y = 0.25;
    } else {
      scene.fog = new THREE.FogExp2(0x0a0a14, 0.055);
      const ambient = new THREE.AmbientLight(0x4c1d95, 0.35);
      scene.add(ambient);
      const key = new THREE.PointLight(0x22d3ee, 1.2, 16);
      key.position.set(1.5, 2, 2);
      scene.add(key);
      const rim = new THREE.PointLight(0xd946ef, 0.85, 14);
      rim.position.set(-2, 0.5, -1);
      scene.add(rim);
      const dir = new THREE.DirectionalLight(0xa78bfa, 0.4);
      dir.position.set(0, 3, 4);
      scene.add(dir);

      bobRefs = buildAiCyberScene(group);
    }

    let rx = 0.1;
    let ry = variant === "indie" ? 0.2 : 0;
    let vx = 0;
    let vy = 0;
    const sens = 0.0052;
    const damping = 0.93;
    const autoRy = variant === "indie" ? 0.0018 : 0.0024;

    let dragging = false;
    let lastX = 0;
    let lastY = 0;

    const onPointerDown = (e: PointerEvent) => {
      dragging = true;
      lastX = e.clientX;
      lastY = e.clientY;
      canvas.setPointerCapture(e.pointerId);
    };
    const onPointerMove = (e: PointerEvent) => {
      if (!dragging) return;
      const dx = e.clientX - lastX;
      const dy = e.clientY - lastY;
      lastX = e.clientX;
      lastY = e.clientY;
      vy += dx * sens;
      vx += dy * sens;
    };
    const onPointerEnd = (e: PointerEvent) => {
      dragging = false;
      try {
        canvas.releasePointerCapture(e.pointerId);
      } catch {
        /* already released */
      }
    };

    canvas.addEventListener("pointerdown", onPointerDown);
    canvas.addEventListener("pointermove", onPointerMove);
    canvas.addEventListener("pointerup", onPointerEnd);
    canvas.addEventListener("pointercancel", onPointerEnd);
    canvas.style.touchAction = "none";

    const resize = () => {
      const w = Math.max(280, container.clientWidth);
      const h = Math.min(440, Math.max(236, Math.round(w * 0.5)));
      camera.aspect = w / h;
      camera.updateProjectionMatrix();
      renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
      renderer.setSize(w, h, false);
    };

    const ro = new ResizeObserver(resize);
    ro.observe(container);
    resize();

    let raf = 0;
    const t0 = performance.now();
    const tick = () => {
      raf = requestAnimationFrame(tick);
      const t = (performance.now() - t0) * 0.001;
      if (!dragging) vy += autoRy;
      rx += vx;
      ry += vy;
      vx *= damping;
      vy *= damping;
      group.rotation.x = rx;
      group.rotation.y = ry;

      if (bobRefs?.robot) {
        bobRefs.robot.position.y = -0.15 + Math.sin(t * 1.8) * 0.035;
      }
      if (bobRefs?.holo) {
        bobRefs.holo.rotation.y = t * 0.9;
        bobRefs.holo.rotation.x = t * 0.45;
      }

      renderer.render(scene, camera);
    };
    tick();

    return () => {
      cancelAnimationFrame(raf);
      ro.disconnect();
      canvas.removeEventListener("pointerdown", onPointerDown);
      canvas.removeEventListener("pointermove", onPointerMove);
      canvas.removeEventListener("pointerup", onPointerEnd);
      canvas.removeEventListener("pointercancel", onPointerEnd);
      scene.fog = null;
      disposeObject3D(group);
      scene.remove(group);
      renderer.dispose();
    };
  }, [variant]);

  const label =
    variant === "indie" ? "独立开发：居家工作台与 homelab 预览" : "AI Agent：赛博空间与机器人预览";

  const hint =
    variant === "indie"
      ? "拖动旋转 · 居家书桌、显示器与 homelab 机架（课程筹备视觉预告）"
      : "拖动旋转 · 赛博网格空间与机器人（课程筹备视觉预告）";

  return (
    <div ref={containerRef} className="mx-auto mt-2 w-full max-w-2xl">
      <p className="mb-2 text-center text-xs text-[var(--muted-foreground)]">{hint}</p>
      <canvas
        ref={canvasRef}
        className="mx-auto block w-full cursor-grab touch-none rounded-2xl border border-[var(--border)] bg-[var(--muted)]/25 active:cursor-grabbing dark:bg-[var(--muted)]/15"
        aria-label={label}
        role="img"
      />
    </div>
  );
}
