<template>
  <n-collapse-item name="drilling" title="钻进工程活动">
    <n-form label-placement="left" label-width="140" size="small">
      <n-form-item label="钻进深度">
        <n-input-number
            v-model:value="drillingParams.depth"
            :max="5"
            :min="0.1"
            :step="0.1"
            style="width: 100%"
        />
      </n-form-item>

      <n-form-item label="动画时长(s)">
        <n-input-number
            v-model:value="drillingParams.drillingDuration"
            :max="30"
            :min="0.5"
            :step="0.5"
            style="width: 100%"
        />
      </n-form-item>

      <n-form-item label="管道半径(m)">
        <n-input-number
            v-model:value="drillingParams.pipeRadius"
            :max="0.5"
            :min="0.05"
            :step="0.01"
            style="width: 100%"
        />
      </n-form-item>
    </n-form>

    <n-space style="width: 100%" vertical>
      <n-button
          :disabled="isSelectingDrillingPoint"
          block
          type="primary"
          @click="startSelectingDrillingPoint">
        {{ isSelectingDrillingPoint ? '请点击场景选择钻进点...' : '选择钻进点' }}
      </n-button>
      <n-button
          :disabled="pipes.length === 0"
          block
          type="error"
          @click="clearAllPipes">
        清除所有管道 ({{ pipes.length }})
      </n-button>
    </n-space>
  </n-collapse-item>
</template>

<script lang="ts" setup>
import {onMounted, ref} from 'vue';
import {NButton, NCollapseItem, NForm, NFormItem, NInputNumber, NSpace} from 'naive-ui';
import {useBus} from '@/hooks';
import {BusEvents} from '@/hooks/Bus.ts';
import {CSGOperationType, CssType, EventManagerEvents, ParametricPipe, Viewer} from '@deep/engine';
import {DrillingHtmlPanel} from '@/htmlPanel';
import * as THREE from 'three/webgpu';

const bus = useBus();
let viewer: Viewer | null = null;
let pipes: ParametricPipe[] = [];
let pipeCounter = 0;
const isSelectingDrillingPoint = ref(false);
const pipeModals = new Map<ParametricPipe, DrillingHtmlPanel>();
let selectedPipe: ParametricPipe | null = null;

// 钻进参数
const drillingParams = ref({
  depth: 2.5,
  drillingDuration: 0.1,
  pipeRadius: 0.1,
});

onMounted(() => {
  bus.once(BusEvents.VIEWER_INITIALIZED).then(() => {
    viewer = bus.getViewer();
    setupClickListener();
  });
});

/**
 * 设置点击事件监听
 */
const setupClickListener = () => {
  if (!viewer) return;

  viewer.events.on(EventManagerEvents.RAYCAST_PICK, ({data}) => {
    if (isSelectingDrillingPoint.value || !viewer) return;

    const {intersects} = data;
    if (!intersects || intersects.length === 0) return;

    for (const intersection of intersects) {
      const clickedObject = intersection.object;
      const pipe = pipes.find(p => p === clickedObject);

      if (pipe) {
        // 如果钻进已完成，不显示弹窗
        if (pipe.options.progress >= 1) {
          break;
        }

        selectedPipe = pipe;
        let modal = pipeModals.get(pipe);
        if (!modal) {
          modal = createDrillingModalForPipe(pipe);
        }
        updateDrillingModalInfo(pipe, modal);
        if (modal && intersection.point) {
          const modalObject = modal.getCssObject();
          const clickPoint = intersection.point;
          modalObject.position.copy(clickPoint);
          modalObject.position.y += 0.5;
        }
        break;
      }
    }
  });
};

/**
 * 为管道创建钻进信息弹窗
 */
const createDrillingModalForPipe = (pipe: ParametricPipe): DrillingHtmlPanel => {
  if (!viewer) throw new Error('Viewer not initialized');

  const modal = new DrillingHtmlPanel(CssType.CSS2D);

  modal.onDelete(() => {
    modal.hide();
    const modalObject = modal.getCssObject();
    if (modalObject.parent) {
      modalObject.parent.remove(modalObject);
    }
    pipeModals.delete(pipe);
    if (selectedPipe === pipe) {
      selectedPipe = null;
    }
  });

  const pipePosition = pipe.position;
  const modalObject = modal.getCssObject();
  modalObject.position.set(pipePosition.x, pipePosition.y + 1, pipePosition.z);
  viewer.scene.add(modalObject);
  modal.show();
  pipeModals.set(pipe, modal);

  return modal;
};

/**
 * 更新钻进信息弹窗内容
 */
const updateDrillingModalInfo = (pipe: ParametricPipe, modal: DrillingHtmlPanel) => {
  const progress = pipe.options.progress * 100;
  const currentDepth = pipe.options.progress * drillingParams.value.depth;
  const status = progress >= 100 ? 'completed' : progress > 0 ? 'drilling' : 'stopped';

  modal.updateData({
    pipeName: pipe.name,
    drillingSpeed: drillingParams.value.drillingDuration,
    currentDepth: currentDepth,
    targetDepth: drillingParams.value.depth,
    progress: progress,
    pipeRadius: pipe.options.radius,
    status: status
  });
};

/**
 * 启动钻进信息实时更新
 */
const startDrillingInfoUpdate = (pipe: ParametricPipe) => {
  const updateInterval = setInterval(() => {
    if (!pipes.includes(pipe)) {
      clearInterval(updateInterval);
      return;
    }

    const modal = pipeModals.get(pipe);
    if (modal) {
      updateDrillingModalInfo(pipe, modal);
    }

    if (pipe.options.progress >= 1) {
      clearInterval(updateInterval);
      if (modal) {
        updateDrillingModalInfo(pipe, modal);
      }
    }
  }, 100);
};

/**
 * 开始选择钻进点
 */
const startSelectingDrillingPoint = () => {
  if (!viewer) return;

  isSelectingDrillingPoint.value = true;
  const canvas = viewer.renderer!.domElement;
  canvas.addEventListener('click', onCanvasClick, {once: true});
  canvas.style.cursor = 'crosshair';
};

/**
 * 处理画布点击事件
 */
const onCanvasClick = (event: MouseEvent) => {
  if (!viewer || !isSelectingDrillingPoint.value) return;

  const canvas = viewer.renderer!.domElement;
  const rect = canvas.getBoundingClientRect();

  const mouse = new THREE.Vector2();
  mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
  mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

  const raycaster = new THREE.Raycaster();
  raycaster.setFromCamera(mouse, viewer.camera);

  const intersects = raycaster.intersectObjects(viewer.scene.children, true);

  if (intersects.length > 0) {
    const intersection = intersects[0];
    if (intersection) {
      createDrillingPipe(intersection.point);
    }
  }

  canvas.style.cursor = 'default';
  isSelectingDrillingPoint.value = false;
};

/**
 * 创建钻进管道
 */
const createDrillingPipe = (startPoint: THREE.Vector3) => {
  if (!viewer) return;

  const points: THREE.Vector3[] = [];
  const topPoint = new THREE.Vector3(startPoint.x, startPoint.y, startPoint.z);
  const bottomPoint = new THREE.Vector3(
      startPoint.x,
      startPoint.y - drillingParams.value.depth,
      startPoint.z
  );

  const segments = 10;
  for (let i = 0; i <= segments; i++) {
    const t = i / segments;
    const y = topPoint.y + (bottomPoint.y - topPoint.y) * t;
    points.push(new THREE.Vector3(startPoint.x, y, startPoint.z));
  }

  const pipeMaterial = new THREE.MeshBasicNodeMaterial({
    color: 0x1b1b1b,
    side: THREE.DoubleSide,
  });

  const newPipe = new ParametricPipe(viewer, {
    points: points,
    radius: drillingParams.value.pipeRadius,
    radialSegments: 16,
    cornerRadius: 0.1,
    cornerSplit: 5,
    progress: 0,
    material: pipeMaterial,
    capStart: false,
    capEnd: false,
    enableDrillingRobot: true,
    robotColor: 0xff0000,
  });
  viewer.scene.add(newPipe);
  pipeCounter++;
  newPipe.name = `钻进管道_${pipeCounter}`;

  newPipe.setCollisionProxyType(true);  // true = 静态
  newPipe.addCollisionTarget(bus.getRockSample(), CSGOperationType.HOLLOW_SUBTRACTION);

  // 存储 ParametricPipe 实例到 mesh.userData，方便其他组件访问
  newPipe.userData.pipeInstance = newPipe;

  pipes.push(newPipe);

  const duration = drillingParams.value.drillingDuration;
  newPipe.setDuration(duration);
  newPipe.startAnimation();

  startDrillingInfoUpdate(newPipe);
  bus.triggerSceneTreeUpdate()
  console.log(newPipe)
};

/**
 * 清除所有管道
 */
const clearAllPipes = () => {
  if (pipes.length > 0) {
    pipes.forEach(pipe => {
      const modal = pipeModals.get(pipe);
      if (modal) {
        modal.hide();
        const modalObject = modal.getCssObject();
        if (modalObject.parent) {
          modalObject.parent.remove(modalObject);
        }
      }
      pipe.dispose();
    });

    pipes = [];
    pipeModals.clear();
    pipeCounter = 0;
    selectedPipe = null;

    bus.triggerSceneTreeUpdate()
  }
};
</script>

<style scoped>

</style>
