"use client";

import { useEffect, useRef, useState } from "react";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { RoomEnvironment } from "three/examples/jsm/environments/RoomEnvironment.js";
import { MeshoptDecoder } from "three/examples/jsm/libs/meshopt_decoder.module.js";
import { createRenderGate } from "@/app/lib/render-gate";
import { Rotate3d, Pause, Play, Maximize2 } from "lucide-react";

type Status = "loading" | "ready" | "error";

/**
 * Trình xem mô hình 3D (.glb) cho cổ vật: xoay, phóng to, tự xoay.
 * Dùng three.js (đã có sẵn trong dự án) — không thêm thư viện mới.
 */
export function AntiquityViewer({ src }: { src: string }) {
  const mountRef = useRef<HTMLDivElement>(null);
  const cameraRef = useRef<THREE.PerspectiveCamera | null>(null);
  const controlsRef = useRef<OrbitControls | null>(null);
  const homeRef = useRef<{ pos: THREE.Vector3; target: THREE.Vector3 } | null>(null);
  const autoRef = useRef(true);

  const [status, setStatus] = useState<Status>("loading");
  const [progress, setProgress] = useState(0);
  const [autoRotate, setAutoRotate] = useState(true);

  useEffect(() => {
    const mount = mountRef.current;
    if (!mount) return;

    setStatus("loading");
    setProgress(0);

    let raf = 0;
    let disposed = false;

    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, powerPreference: "high-performance" });
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.5));
    renderer.toneMapping = THREE.ACESFilmicToneMapping;
    renderer.toneMappingExposure = 1.08;
    renderer.domElement.style.cssText = "width:100%;height:100%;display:block;cursor:grab;";
    mount.appendChild(renderer.domElement);

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(40, 1, 0.01, 1000);
    cameraRef.current = camera;

    const pmrem = new THREE.PMREMGenerator(renderer);
    const envTexture = pmrem.fromScene(new RoomEnvironment(), 0.04).texture;
    scene.environment = envTexture;

    const keyLight = new THREE.DirectionalLight(0xfff1d6, 2.4);
    keyLight.position.set(2.5, 3.5, 2.2);
    const rimLight = new THREE.DirectionalLight(0xcdd9ff, 1.2);
    rimLight.position.set(-3, 1.8, -2.4);
    const ambient = new THREE.AmbientLight(0xffffff, 0.3);
    scene.add(keyLight, rimLight, ambient);

    const controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.08;
    controls.enablePan = false;
    controls.autoRotate = autoRef.current;
    controls.autoRotateSpeed = 1.1;
    controls.addEventListener("start", () => {
      renderer.domElement.style.cursor = "grabbing";
    });
    controls.addEventListener("end", () => {
      renderer.domElement.style.cursor = "grab";
    });
    controlsRef.current = controls;

    let needsRender = true;
    let active = true;
    const requestRender = () => {
      needsRender = true;
    };
    controls.addEventListener("change", requestRender);

    const stopGate = createRenderGate(mount, (isActive) => {
      active = isActive;
      if (isActive) requestRender();
    });

    const resize = () => {
      const w = mount.clientWidth;
      const h = mount.clientHeight;
      if (!w || !h) return;
      renderer.setSize(w, h, false);
      camera.aspect = w / h;
      camera.updateProjectionMatrix();
      needsRender = true;
    };
    const observer = new ResizeObserver(resize);
    observer.observe(mount);
    resize();

    const loader = new GLTFLoader();
    loader.setMeshoptDecoder(MeshoptDecoder);
    loader.load(
      src,
      (gltf) => {
        if (disposed) return;
        const model = gltf.scene;

        const box = new THREE.Box3().setFromObject(model);
        const size = box.getSize(new THREE.Vector3());
        const center = box.getCenter(new THREE.Vector3());
        model.position.sub(center);

        const maxDim = Math.max(size.x, size.y, size.z) || 1;
        model.scale.setScalar(2 / maxDim);
        scene.add(model);

        const radius = 1; // mô hình đã chuẩn hóa về ~2 đơn vị
        const dist = (radius / Math.sin((camera.fov * Math.PI) / 360)) * 1.25;
        camera.position.set(dist * 0.62, dist * 0.32, dist * 0.92);
        controls.target.set(0, 0, 0);
        controls.minDistance = dist * 0.55;
        controls.maxDistance = dist * 2.6;
        controls.update();

        homeRef.current = { pos: camera.position.clone(), target: controls.target.clone() };
        setStatus("ready");
        requestRender();
      },
      (event) => {
        if (event.total) setProgress(Math.round((event.loaded / event.total) * 100));
      },
      () => {
        if (!disposed) setStatus("error");
      },
    );

    const tick = () => {
      raf = requestAnimationFrame(tick);
      if (!active) return;
      // controls.update() trả về true khi camera còn chuyển động (damping/autoRotate)
      const moving = controls.update();
      if (needsRender || moving || controls.autoRotate) {
        renderer.render(scene, camera);
        needsRender = false;
      }
    };
    tick();

    return () => {
      disposed = true;
      cancelAnimationFrame(raf);
      observer.disconnect();
      stopGate();
      controls.removeEventListener("change", requestRender);
      controls.dispose();
      scene.traverse((object) => {
        const mesh = object as THREE.Mesh;
        if (mesh.geometry) mesh.geometry.dispose();
        const material = mesh.material;
        if (Array.isArray(material)) material.forEach((m) => m.dispose());
        else if (material) (material as THREE.Material).dispose();
      });
      envTexture.dispose();
      pmrem.dispose();
      renderer.dispose();
      if (renderer.domElement.parentNode === mount) mount.removeChild(renderer.domElement);
    };
  }, [src]);

  const toggleAutoRotate = () => {
    const next = !autoRotate;
    setAutoRotate(next);
    autoRef.current = next;
    if (controlsRef.current) controlsRef.current.autoRotate = next;
  };

  const resetView = () => {
    const camera = cameraRef.current;
    const controls = controlsRef.current;
    const home = homeRef.current;
    if (!camera || !controls || !home) return;
    camera.position.copy(home.pos);
    controls.target.copy(home.target);
    controls.update();
  };

  return (
    <div className="relative h-full w-full overflow-hidden rounded-[14px]">
      <div
        ref={mountRef}
        className="h-full w-full"
        style={{
          background:
            "radial-gradient(circle at 50% 36%, rgb(63 70 54 / 0.55), rgb(18 21 16 / 0.92) 72%)",
        }}
      />

      {status === "loading" ? (
        <div className="absolute inset-0 grid place-items-center bg-[rgb(18_21_16_/_0.55)] backdrop-blur-[2px]">
          <div className="flex flex-col items-center gap-3 text-center">
            <span className="grid h-12 w-12 animate-spin place-items-center rounded-full border-2 border-[rgb(200_164_106_/_0.25)] border-t-[var(--primary)]" />
            <p className="text-sm font-semibold text-[var(--tour-ink)]">Đang tải mô hình 3D… {progress > 0 ? `${progress}%` : ""}</p>
            <p className="max-w-[24ch] text-xs text-[var(--muted-foreground)]">Hiện vật độ phân giải cao, vui lòng đợi trong giây lát.</p>
          </div>
        </div>
      ) : null}

      {status === "error" ? (
        <div className="absolute inset-0 grid place-items-center bg-[rgb(18_21_16_/_0.7)]">
          <p className="max-w-[28ch] px-6 text-center text-sm font-semibold text-[var(--tour-ink)]">
            Không tải được mô hình 3D. Vui lòng kiểm tra kết nối và thử lại.
          </p>
        </div>
      ) : null}

      {status === "ready" ? (
        <>
          <div className="pointer-events-none absolute left-1/2 top-4 -translate-x-1/2 rounded-full border border-[rgb(215_199_157_/_0.18)] bg-[rgb(18_21_16_/_0.55)] px-3.5 py-1.5 text-[0.72rem] font-medium text-[var(--tour-ink)] backdrop-blur-md">
            Kéo để xoay · Lăn chuột để phóng to
          </div>
          <div className="absolute bottom-4 right-4 flex gap-2">
            <button
              type="button"
              onClick={toggleAutoRotate}
              aria-label={autoRotate ? "Tạm dừng tự xoay" : "Bật tự xoay"}
              className="grid h-10 w-10 place-items-center rounded-full border border-[rgb(215_199_157_/_0.22)] bg-[rgb(18_21_16_/_0.6)] text-[var(--tour-ink)] backdrop-blur-md transition hover:border-[var(--primary)] hover:text-[var(--primary)] focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[rgb(200_164_106_/_0.25)]"
            >
              {autoRotate ? <Pause className="h-4 w-4" strokeWidth={1.8} /> : <Play className="h-4 w-4" strokeWidth={1.8} />}
            </button>
            <button
              type="button"
              onClick={resetView}
              aria-label="Đặt lại góc nhìn"
              className="grid h-10 w-10 place-items-center rounded-full border border-[rgb(215_199_157_/_0.22)] bg-[rgb(18_21_16_/_0.6)] text-[var(--tour-ink)] backdrop-blur-md transition hover:border-[var(--primary)] hover:text-[var(--primary)] focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[rgb(200_164_106_/_0.25)]"
            >
              <Maximize2 className="h-4 w-4" strokeWidth={1.8} />
            </button>
          </div>
          <div className="pointer-events-none absolute bottom-4 left-4 inline-flex items-center gap-1.5 text-[0.7rem] font-semibold uppercase tracking-[0.14em] text-[rgb(248_242_229_/_0.62)]">
            <Rotate3d className="h-3.5 w-3.5" strokeWidth={1.8} />
            Mô hình 3D
          </div>
        </>
      ) : null}
    </div>
  );
}
