import * as TWEEN from "@tweenjs/tween.js";
import { toRaw } from "vue";

const THREE = window.THREE;
let rafId = null;

/**
 * 相機沿弧線飛行
 */
function flyArc(param) {
  const {
    viewer,
    fromPos,
    fromTarget,
    toPos,
    toTarget,
    label,
    returnToOriginal = false,
    duration = 3000,
    item,
    arcSide = -1,
  } = param;
  const nav = viewer.navigation;

  // 中間控制點（弧線）
  const distance = fromPos.distanceTo(toPos);

  const forward = toPos.clone().sub(fromPos).normalize();

  const up = new THREE.Vector3(0, 1, 0);

  const side = new THREE.Vector3().crossVectors(forward, up).normalize();

  const midPos = fromPos.clone().lerp(toPos, 0.5);

  // ⭐ 控制左右方向
  midPos.add(side.multiplyScalar(distance * arcSide * 0.7));

  const curve = new THREE.QuadraticBezierCurve3(fromPos, midPos, toPos);

  const tweenObj = { t: 0 };

  const tween = new TWEEN.Tween(tweenObj)
    .to({ t: 1 }, duration)
    .easing(TWEEN.Easing.Cubic.InOut)
    .onStart(() => {
      if (returnToOriginal) {
        label.classList.remove("flex");
        label.classList.add("hidden");
      }
    })
    .onUpdate(() => {
      const point = curve.getPoint(tweenObj.t);
      nav.setPosition(point);

      const target = fromTarget.clone().lerp(toTarget, tweenObj.t);
      nav.setTarget(target);
    })
    .onComplete(() => {
      console.log("飛行完成", label.classList, returnToOriginal);

      if (!returnToOriginal) {
        label.querySelector(".tag_name").textContent = item.title;
        label.classList.remove("hidden");
        label.classList.add("flex");
      }
    })
    .start();

  function animate(time) {
    if (rafId) {
      cancelAnimationFrame(rafId);
      rafId = null;
    }
    rafId = requestAnimationFrame(animate);
    tween.update(time);
  }
  animate();
}

/**
 * 取得物件 BoundingBox
 */
function getObjectBoundingBox(viewer, dbId) {
  const THREE = window.THREE;
  const model = viewer.model;
  const tree = model.getInstanceTree();
  const fragList = model.getFragmentList();
  const bbox = new THREE.Box3();

  tree.enumNodeFragments(
    dbId,
    (fragId) => {
      const fragBox = new THREE.Box3();
      fragList.getWorldBounds(fragId, fragBox);
      bbox.union(fragBox);
    },
    true,
  );

  return bbox;
}

/**
 * 計算相機最佳距離（物件越大，相機越遠）
 */
function computeCameraOffset(viewer, bbox, distanceMultiplier = 7) {
  const THREE = window.THREE;
  const nav = viewer.navigation;

  const center = bbox.getCenter(new THREE.Vector3());
  const size = bbox.getSize(new THREE.Vector3());

  const maxDim = Math.max(size.x, size.y, size.z);

  // FOV
  const fov = (nav.getVerticalFov() * Math.PI) / 180;

  let distance = maxDim / (2 * Math.tan(fov / 2));

  // 拉遠一點
  distance *= distanceMultiplier;

  // ⭐ 固定斜上角方向（超重要）
  const direction = new THREE.Vector3(-0.35, -0.5, 1).normalize();

  // ⭐ 相機位置
  const position = center.clone().add(direction.multiplyScalar(distance));

  return {
    position,
    target: center,
  };
}

function showByName(v, id) {
  v.hideAll();
  v.show(id);
}

// 取得樓層
function isolateFloor(viewer, minZ, maxZ) {
  const model = viewer.model;
  const tree = model.getInstanceTree();
  const fragList = model.getFragmentList();
  const THREE = window.THREE;

  const visibleDbIds = [];

  tree.enumNodeChildren(
    tree.getRootId(),
    (dbId) => {
      if (tree.getChildCount(dbId) !== 0) return;

      const bbox = new THREE.Box3();

      tree.enumNodeFragments(dbId, (fragId) => {
        const fragBox = new THREE.Box3();
        fragList.getWorldBounds(fragId, fragBox);
        bbox.union(fragBox);
      });

      const centerZ = bbox.getCenter(new THREE.Vector3()).z;

      if (centerZ >= minZ && centerZ <= maxZ) {
        visibleDbIds.push(dbId);
      }
    },
    true,
  );

  viewer.hideAll();

  viewer.setGhosting(false); // ⭐ 關鍵
  viewer.isolate(visibleDbIds);
}

/**
 * 主功能：飛到物件 → 再飛回原點
 */

export default function changeCameraPosition(forgeViewer, label, item) {
  const viewer = toRaw(forgeViewer);

  console.log("切換視角到物件:", item);
  showByName(viewer, item.parent);

  // isolateFloor(viewer, -3000, 0); // 單位看你的模型

  const nav = viewer.navigation;

  // ⭐ 記錄相機初始位置與 target
  const initialPos = nav.getPosition().clone();
  const initialTarget = nav.getTarget().clone();

  // ⭐ 取得物件資訊
  const bbox = getObjectBoundingBox(viewer, item.forgeID);
  const center = bbox.getCenter(new THREE.Vector3());

  console.log("物件中心:", center);

  // ⭐ 計算最佳觀察點
  const { position, target } = computeCameraOffset(
    viewer,
    bbox,
    item.cameraDistance,
  );

  // ⭐ 第 1 段：飛到物件
  const toTarget = {
    viewer,
    fromPos: initialPos,
    fromTarget: initialTarget,
    toPos: position,
    toTarget: target,
    label,
    returnToOriginal: false,
    duration: 5000,
    item,
    arcSide: item.arcSide,
  };
  flyArc(toTarget);

  // ⭐ 第 2 段：停 0.5 秒後飛回原點
  setTimeout(() => {
    const toOriginal = {
      viewer,
      fromPos: position,
      fromTarget: target,
      toPos: initialPos,
      toTarget: initialTarget,
      label,
      returnToOriginal: true,
      duration: 5000,
      item,
      arcSide: -item.arcSide,
    };
    flyArc(toOriginal);
    viewer.model.getInstanceTree().enumNodeChildren(
      item.forgeID,
      (dbId) => {
        viewer.setThemingColor(dbId, null); // RGBA (紅色));
        viewer.impl.invalidate(true);
      },
      true,
    );
    viewer.showAll(); // 恢復顯示所有物件
  }, 8000);
}
