"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());
}

function applyFilmicRenderer(renderer: THREE.WebGLRenderer, exposure: number) {
  renderer.outputColorSpace = THREE.SRGBColorSpace;
  renderer.toneMapping = THREE.ACESFilmicToneMapping;
  renderer.toneMappingExposure = exposure;
}

/** 独立开发：三面墙+顶+地 半封闭小房间（朝镜头开口），萌系配色与小狗 */
function buildIndieEnclosedRoom(root: THREE.Group): { dog: THREE.Group; tail: THREE.Mesh } {
  const wall = new THREE.MeshStandardMaterial({
    color: 0xfff0f3,
    roughness: 0.94,
    metalness: 0,
  });
  const floorMat = new THREE.MeshStandardMaterial({
    color: 0xf5e0d4,
    roughness: 0.88,
    metalness: 0,
  });
  const ceilMat = new THREE.MeshStandardMaterial({
    color: 0xfff7fb,
    roughness: 0.92,
    metalness: 0,
  });

  const floor = new THREE.Mesh(new THREE.PlaneGeometry(5.2, 4.2), floorMat);
  floor.rotation.x = -Math.PI / 2;
  floor.position.y = -1;
  root.add(floor);

  const back = new THREE.Mesh(new THREE.PlaneGeometry(5.2, 3.2), wall);
  back.position.set(0, 0.6, -2.1);
  root.add(back);

  const left = new THREE.Mesh(new THREE.PlaneGeometry(4.2, 3.2), wall);
  left.rotation.y = Math.PI / 2;
  left.position.set(-2.6, 0.6, 0);
  root.add(left);

  const right = new THREE.Mesh(new THREE.PlaneGeometry(4.2, 3.2), wall);
  right.rotation.y = -Math.PI / 2;
  right.position.set(2.6, 0.6, 0);
  root.add(right);

  const ceiling = new THREE.Mesh(new THREE.PlaneGeometry(5.2, 4.2), ceilMat);
  ceiling.rotation.x = Math.PI / 2;
  ceiling.position.y = 2.2;
  root.add(ceiling);

  const lamp = new THREE.Mesh(
    new THREE.PlaneGeometry(1.4, 0.9),
    new THREE.MeshStandardMaterial({
      color: 0xffffff,
      emissive: 0xfff1f2,
      emissiveIntensity: 0.55,
      roughness: 1,
    }),
  );
  lamp.rotation.x = Math.PI / 2;
  lamp.position.set(0, 2.18, 0.2);
  root.add(lamp);

  const deskMat = new THREE.MeshStandardMaterial({
    color: 0xf5e6d8,
    roughness: 0.5,
    metalness: 0.04,
  });
  const deskTop = new THREE.Mesh(new THREE.BoxGeometry(1.65, 0.055, 0.72), deskMat);
  deskTop.position.set(-0.25, -0.45, 0.05);
  root.add(deskTop);

  const legGeo = new THREE.CylinderGeometry(0.038, 0.042, 0.36, 14);
  const legMat = new THREE.MeshStandardMaterial({ color: 0xe8d5c4, roughness: 0.58 });
  for (const [x, z] of [
    [-0.72, -0.22],
    [0.22, -0.22],
    [-0.72, 0.38],
    [0.22, 0.38],
  ]) {
    const leg = new THREE.Mesh(legGeo, legMat);
    leg.position.set(x, -0.66, z);
    root.add(leg);
  }

  const bezel = new THREE.MeshStandardMaterial({
    color: 0x3f3f46,
    roughness: 0.42,
    metalness: 0.12,
  });
  const monitor = new THREE.Mesh(new THREE.BoxGeometry(0.62, 0.42, 0.028), bezel);
  monitor.position.set(-0.25, -0.08, -0.38);
  root.add(monitor);

  const screenMat = new THREE.MeshStandardMaterial({
    color: 0xa5d8ff,
    emissive: 0xc5eaff,
    emissiveIntensity: 0.28,
    roughness: 0.4,
  });
  const screen = new THREE.Mesh(new THREE.PlaneGeometry(0.56, 0.36), screenMat);
  screen.position.set(-0.25, -0.08, -0.38 + 0.015);
  root.add(screen);

  const kb = new THREE.Mesh(
    new THREE.BoxGeometry(0.48, 0.022, 0.18),
    new THREE.MeshStandardMaterial({ color: 0xa8a29e, roughness: 0.55 }),
  );
  kb.position.set(-0.25, -0.4, 0.22);
  kb.rotation.x = -0.035;
  root.add(kb);

  const tower = new THREE.Mesh(
    new THREE.BoxGeometry(0.18, 0.36, 0.32),
    new THREE.MeshStandardMaterial({ color: 0xfafafa, roughness: 0.32 }),
  );
  tower.position.set(0.38, -0.38, -0.28);
  root.add(tower);

  const chairSeat = new THREE.Mesh(
    new THREE.BoxGeometry(0.4, 0.055, 0.36),
    new THREE.MeshStandardMaterial({ color: 0x78716c, roughness: 0.72 }),
  );
  chairSeat.position.set(-0.25, -0.72, 0.55);
  root.add(chairSeat);

  const fur = new THREE.MeshStandardMaterial({
    color: 0xffc4a8,
    roughness: 0.82,
    metalness: 0,
  });
  const furDeep = new THREE.MeshStandardMaterial({
    color: 0xf59e7c,
    roughness: 0.85,
    metalness: 0,
  });

  const dog = new THREE.Group();
  dog.position.set(0.75, -0.86, 0.22);

  const body = new THREE.Mesh(new THREE.SphereGeometry(0.2, 22, 18), fur);
  body.scale.set(1.05, 0.78, 1.12);
  body.position.y = 0.11;
  dog.add(body);

  const head = new THREE.Mesh(new THREE.SphereGeometry(0.16, 20, 18), fur);
  head.position.set(0, 0.3, 0.1);
  dog.add(head);

  const snout = new THREE.Mesh(new THREE.SphereGeometry(0.065, 14, 14), furDeep);
  snout.position.set(0, 0.26, 0.22);
  snout.scale.set(1, 0.88, 1.15);
  dog.add(snout);

  const nose = new THREE.Mesh(
    new THREE.SphereGeometry(0.022, 10, 10),
    new THREE.MeshStandardMaterial({ color: 0x292524, roughness: 0.35 }),
  );
  nose.position.set(0, 0.28, 0.3);
  dog.add(nose);

  const eyeWhiteL = new THREE.Mesh(
    new THREE.SphereGeometry(0.045, 12, 12),
    new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.25 }),
  );
  eyeWhiteL.position.set(-0.055, 0.32, 0.18);
  const eyeWhiteR = eyeWhiteL.clone();
  eyeWhiteR.position.x = 0.055;
  dog.add(eyeWhiteL, eyeWhiteR);

  const pupilL = new THREE.Mesh(
    new THREE.SphereGeometry(0.022, 10, 10),
    new THREE.MeshStandardMaterial({ color: 0x1c1917, roughness: 0.2 }),
  );
  pupilL.position.set(-0.052, 0.32, 0.2);
  const pupilR = pupilL.clone();
  pupilR.position.x = 0.052;
  dog.add(pupilL, pupilR);

  const blushMat = new THREE.MeshStandardMaterial({
    color: 0xff9eb5,
    roughness: 0.6,
    emissive: 0xff8fab,
    emissiveIntensity: 0.12,
  });
  const blushL = new THREE.Mesh(new THREE.SphereGeometry(0.035, 10, 10), blushMat);
  blushL.scale.set(1.2, 0.45, 0.6);
  blushL.position.set(-0.1, 0.24, 0.16);
  const blushR = blushL.clone();
  blushR.position.x = 0.1;
  dog.add(blushL, blushR);

  const earL = new THREE.Mesh(new THREE.SphereGeometry(0.055, 12, 12), furDeep);
  earL.position.set(-0.11, 0.36, 0.05);
  earL.scale.set(0.45, 0.95, 0.4);
  const earR = earL.clone();
  earR.position.x = 0.11;
  dog.add(earL, earR);

  const tail = new THREE.Mesh(
    new THREE.CylinderGeometry(0.028, 0.036, 0.2, 12),
    furDeep,
  );
  tail.rotation.z = Math.PI / 2.8;
  tail.rotation.x = 0.25;
  tail.position.set(-0.18, 0.16, -0.06);
  dog.add(tail);

  for (const [x, z] of [
    [-0.09, 0.07],
    [0.09, 0.07],
    [-0.07, -0.07],
    [0.07, -0.07],
  ]) {
    const paw = new THREE.Mesh(new THREE.SphereGeometry(0.048, 12, 12), furDeep);
    paw.scale.set(1, 0.58, 1);
    paw.position.set(x, 0, z);
    dog.add(paw);
  }

  root.add(dog);
  return { dog, tail };
}

/** AI：赛博空间，无网格线；萌系圆润机器人 + 实体光晕环（非线框） */
function buildAiCuteCyber(root: THREE.Group): {
  bot: THREE.Group;
  halo: THREE.Mesh;
  orbs: THREE.Mesh[];
} {
  const backdrop = new THREE.Mesh(
    new THREE.SphereGeometry(16, 48, 48),
    new THREE.MeshBasicMaterial({ color: 0x0c0618, side: THREE.BackSide }),
  );
  root.add(backdrop);

  const floor = new THREE.Mesh(
    new THREE.CircleGeometry(4.5, 64),
    new THREE.MeshStandardMaterial({
      color: 0x1e1435,
      roughness: 0.55,
      metalness: 0.15,
      emissive: 0x4c1d95,
      emissiveIntensity: 0.06,
    }),
  );
  floor.rotation.x = -Math.PI / 2;
  floor.position.y = -1.05;
  root.add(floor);

  const haloMat = new THREE.MeshStandardMaterial({
    color: 0xa78bfa,
    emissive: 0x8b5cf6,
    emissiveIntensity: 0.25,
    roughness: 0.35,
    metalness: 0.25,
    transparent: true,
    opacity: 0.55,
    side: THREE.DoubleSide,
  });
  const halo = new THREE.Mesh(new THREE.TorusGeometry(1.05, 0.035, 16, 64), haloMat);
  halo.rotation.x = Math.PI / 2;
  halo.position.y = -0.35;
  root.add(halo);

  const shell = new THREE.MeshStandardMaterial({
    color: 0xe8e0ff,
    roughness: 0.42,
    metalness: 0.18,
  });
  const shellDark = new THREE.MeshStandardMaterial({
    color: 0xc4b5fd,
    roughness: 0.45,
    metalness: 0.22,
  });
  const eyeGlow = new THREE.MeshStandardMaterial({
    color: 0x67e8f9,
    emissive: 0x22d3ee,
    emissiveIntensity: 0.35,
    roughness: 0.28,
  });

  const bot = new THREE.Group();
  bot.position.set(0, -0.25, 0);

  const body = new THREE.Mesh(new THREE.SphereGeometry(0.32, 28, 24), shell);
  body.scale.set(1, 0.88, 0.92);
  body.position.y = 0.05;
  bot.add(body);

  const tummy = new THREE.Mesh(new THREE.CircleGeometry(0.18, 24), shellDark);
  tummy.rotation.x = -0.15;
  tummy.position.set(0, 0.02, 0.27);
  bot.add(tummy);

  const head = new THREE.Mesh(new THREE.SphereGeometry(0.26, 28, 24), shell);
  head.position.y = 0.48;
  bot.add(head);

  const eyeWL = new THREE.Mesh(new THREE.SphereGeometry(0.07, 14, 14), new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.2 }));
  eyeWL.position.set(-0.08, 0.5, 0.22);
  const eyeWR = eyeWL.clone();
  eyeWR.position.x = 0.08;
  bot.add(eyeWL, eyeWR);

  const eyeL = new THREE.Mesh(new THREE.SphereGeometry(0.038, 12, 12), eyeGlow);
  eyeL.position.set(-0.078, 0.5, 0.26);
  const eyeR = eyeL.clone();
  eyeR.position.x = 0.078;
  bot.add(eyeL, eyeR);

  const cheek = new THREE.MeshStandardMaterial({
    color: 0xf9a8d4,
    emissive: 0xf472b6,
    emissiveIntensity: 0.15,
    roughness: 0.5,
  });
  const chL = new THREE.Mesh(new THREE.SphereGeometry(0.04, 10, 10), cheek);
  chL.scale.set(1.3, 0.5, 0.5);
  chL.position.set(-0.14, 0.42, 0.2);
  const chR = chL.clone();
  chR.position.x = 0.14;
  bot.add(chL, chR);

  const antStem = new THREE.Mesh(
    new THREE.CylinderGeometry(0.02, 0.025, 0.16, 10),
    shellDark,
  );
  antStem.position.set(0, 0.72, 0);
  bot.add(antStem);
  const antBall = new THREE.Mesh(new THREE.SphereGeometry(0.055, 16, 16), eyeGlow);
  antBall.position.set(0, 0.82, 0);
  bot.add(antBall);

  const armGeo = new THREE.CapsuleGeometry(0.07, 0.22, 6, 12);
  const armL = new THREE.Mesh(armGeo, shell);
  armL.position.set(-0.42, 0.08, 0);
  armL.rotation.z = 0.35;
  const armR = new THREE.Mesh(armGeo, shell);
  armR.position.set(0.42, 0.08, 0);
  armR.rotation.z = -0.35;
  bot.add(armL, armR);

  const leg = new THREE.Mesh(new THREE.CapsuleGeometry(0.09, 0.12, 6, 12), shellDark);
  leg.position.set(-0.12, -0.32, 0.05);
  const leg2 = leg.clone();
  leg2.position.x = 0.12;
  bot.add(leg, leg2);

  root.add(bot);

  const orbMat = [
    new THREE.MeshStandardMaterial({ color: 0xf0abfc, roughness: 0.35, metalness: 0.2 }),
    new THREE.MeshStandardMaterial({ color: 0x7dd3fc, roughness: 0.35, metalness: 0.2 }),
    new THREE.MeshStandardMaterial({ color: 0xfde68a, roughness: 0.35, metalness: 0.15 }),
  ];
  const orbs: THREE.Mesh[] = [];
  for (let i = 0; i < 3; i++) {
    const o = new THREE.Mesh(new THREE.SphereGeometry(0.09, 16, 16), orbMat[i]);
    const a = (i / 3) * Math.PI * 2;
    o.position.set(Math.cos(a) * 1.15, 0.25 + i * 0.08, Math.sin(a) * 1.15);
    root.add(o);
    orbs.push(o);
  }

  return { bot, halo, orbs };
}

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: false,
      powerPreference: "high-performance",
    });

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

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

    let anim: {
      dog?: THREE.Group;
      tail?: THREE.Mesh;
      bot?: THREE.Group;
      halo?: THREE.Mesh;
      orbs?: THREE.Mesh[];
    } | null = null;

    if (variant === "indie") {
      scene.fog = new THREE.Fog(0xfff5f7, 3.8, 11);
      applyFilmicRenderer(renderer, 1.02);

      const hemi = new THREE.HemisphereLight(0xffffff, 0xfce7f3, 0.95);
      scene.add(hemi);
      const key = new THREE.DirectionalLight(0xffffff, 0.48);
      key.position.set(2, 5, 3);
      scene.add(key);
      const fill = new THREE.DirectionalLight(0xffe4e8, 0.28);
      fill.position.set(-3, 2, -1);
      scene.add(fill);
      const scr = new THREE.PointLight(0xbfdbfe, 0.35, 5);
      scr.position.set(-0.25, 0, 0);
      scene.add(scr);

      anim = buildIndieEnclosedRoom(group);
      group.rotation.set(0.1, 0.28, 0);
    } else {
      scene.fog = new THREE.FogExp2(0x0c0618, 0.048);
      applyFilmicRenderer(renderer, 1.05);

      const hemi = new THREE.HemisphereLight(0xc4b5fd, 0x1e1038, 0.75);
      scene.add(hemi);
      const key = new THREE.DirectionalLight(0xf5f3ff, 0.5);
      key.position.set(2, 4.5, 3);
      scene.add(key);
      const rim = new THREE.DirectionalLight(0x7c3aed, 0.22);
      rim.position.set(-2.5, 1, -1.5);
      scene.add(rim);
      const glow = new THREE.PointLight(0xa78bfa, 0.4, 9);
      glow.position.set(0.8, 1.2, 1);
      scene.add(glow);

      anim = buildAiCuteCyber(group);
      group.rotation.set(0.06, -0.15, 0);
    }

    let rx = group.rotation.x;
    let ry = group.rotation.y;
    let vx = 0;
    let vy = 0;
    const sens = 0.0046;
    const damping = 0.936;
    const autoRy = variant === "indie" ? 0.001 : 0.0013;

    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(240, Math.round(w * 0.52)));
      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 (anim?.dog) {
        anim.dog.position.y = -0.86 + Math.sin(t * 2) * 0.016;
        anim.dog.rotation.y = Math.sin(t * 0.85) * 0.05;
      }
      if (anim?.tail) {
        anim.tail.rotation.z = Math.PI / 2.8 + Math.sin(t * 4.5) * 0.22;
      }
      if (anim?.bot) {
        anim.bot.position.y = -0.25 + Math.sin(t * 1.5) * 0.03;
        anim.bot.rotation.y = Math.sin(t * 0.6) * 0.04;
      }
      if (anim?.halo) {
        anim.halo.rotation.z = t * 0.15;
      }
      if (anim?.orbs) {
        anim.orbs.forEach((o, i) => {
          const a = t * 0.5 + (i / 3) * Math.PI * 2;
          o.position.y = 0.25 + i * 0.08 + Math.sin(t * 1.8 + i) * 0.06;
          o.position.x = Math.cos(a) * 1.15;
          o.position.z = Math.sin(a) * 1.15;
        });
      }

      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" ? "独立开发互动预览" : "AI Agent 互动预览";

  return (
    <div ref={containerRef} className="mx-auto mt-2 w-full max-w-2xl">
      <canvas
        ref={canvasRef}
        className="mx-auto block w-full cursor-grab touch-none rounded-2xl shadow-md outline-none active:cursor-grabbing dark:shadow-lg dark:shadow-violet-950/20"
        aria-label={label}
        role="img"
      />
    </div>
  );
}
