<template>
    <div ref="map_container_ref" :class="['three-map', props.className]" :style="{
        width: props.width,
        height: props.height
    }"></div>
</template>

<script setup lang="ts">
import { useInitThree } from "./useInitThree";
import { ref, watch, onMounted, shallowRef, inject,toRaw } from "vue";
import { useGLTFLoader } from "@/hooks/useGLTFLoader";
import {
    Group,
    Mesh,
    MeshBasicMaterial,
    Vector3,
    SphereGeometry,
    Sprite,
    TextureLoader,
    Texture, RepeatWrapping, Box3
} from "three";
import { useRayCast } from "./useRayCast";
import { coordinate_src, cycle_light_src, Floor } from "./Constants";
import { createImgSprite, createSphere, useConnectPoint } from "@/hooks/useMesh";
import { getRandomIntInclusive, isMesh } from "@/hooks/Utils";
import { connect_point_inject_key } from "../../global";
import { Character } from "../Character/Character";
import { character_src } from "../Character/Constants";
import { PathFinder } from "../PathFinder/PathFinder";

const props = defineProps<{
    className: string,
    width: string,
    height: string,
    floorId: string,
}>();
const {
    map_conn_points,
    graph
} = inject(connect_point_inject_key)!;

// 坐标点texture
const texture_loader = new TextureLoader();
let coordinate_texture: Texture | undefined;
texture_loader.load(coordinate_src, (texture) => {
    coordinate_texture = texture;
});

// 连通点texture
let cycle_light_texture: Texture | undefined;
texture_loader.load(cycle_light_src, (texture) => {
    cycle_light_texture = texture;
    cycle_light_texture.wrapS = RepeatWrapping;
    cycle_light_texture.repeat.set(2, 1);
});

const cur_map = shallowRef<Group | null>(null);

const map_file_cache: Record<string, Group> = {};

// 选择的坐标点Mesh（起始点/终点）
const startPoint = shallowRef<Group | null>(null);

const endPoint = shallowRef<Group | null>(null);

let ray_cast: ReturnType<typeof useRayCast> | null = null;

const map_container_ref = ref<HTMLElement>();

const {
    scene,
    camera,
    renderer,
    clock,
    controls,
    renderCSS2D
} = useInitThree(map_container_ref);
const character = new Character(camera, scene, character_src, new Vector3(0, 0, 0));

const path_finder = new PathFinder();
// 连通点
const { renderConnectPoint } = useConnectPoint(scene);

// 切换地图
const setfloorId = async (scene_url: string) => {
    if (cur_map.value) {
        cur_map.value.traverse(item => {
            if (isMesh(item)) {
                item.material.dispose();
            }
        });

        clearPointHelper();

        scene.remove(cur_map.value);
    }

    let map: Group;

    if (map_file_cache[scene_url]) {
        map = map_file_cache[scene_url];
    } else {
        map = (await useGLTFLoader(Floor[scene_url])).scene;
        map_file_cache[scene_url] = map;
    }

    map.traverse(item => {
        console.log(item);

        if (isMesh(item) && item.name.includes("NavMesh")) {
            item.material.visible = false;
            path_finder.setZoneData(props.floorId, item);
        }
    });

    cur_map.value = map;
    scene.add(map);
    const bbox = new Box3().setFromObject(map);
    const center = new Vector3();
    bbox.getCenter(center);
    // 设置控制器目标点为模型中心
    controls.target.copy(center);
    camera.position.copy(center).add(new Vector3(0, 60, 50)); //3d视角
    controls.update();
    // renderConnectPoint(map_conn_points.get(scene_url)!, graph.getAdjList(), cycle_light_texture as Texture);

    if (ray_cast) {
        if (!ray_cast.intersect.value) {
            ray_cast.onRayCast(map, handleMapClick);
        } else {
            ray_cast.setIntersect(map);
        }
    }
};
const switch3D = (is3D) => {
    const bbox = new Box3().setFromObject(cur_map.value);
    const center = new Vector3();
    bbox.getCenter(center);
    controls.target.copy(center);
    if (is3D) {
        camera.position.copy(center).add(new Vector3(0, 60, 50)); //3d视角
        controls.update();
    } else {
        camera.position.copy(center).add(new Vector3(0, 75, 0)); //2d视角
        controls.update();
    }
}
onMounted(() => {
    ray_cast = useRayCast(map_container_ref.value as HTMLElement, camera);

    watch(() => props.floorId, setfloorId, { immediate: true });
});

const clearPointHelper = () => {
    if (startPoint.value) {
        // const sphere = select_point.value.getObjectByName("sphere") as Mesh<SphereGeometry, MeshBasicMaterial>;
        const sprite = startPoint.value.getObjectByName("sprite") as Sprite;
        // sphere.material.dispose();
        sprite.material.dispose();
        scene.remove(startPoint.value);

        startPoint.value = null;
    }
    if (endPoint.value) {
        // const sphere = select_point.value.getObjectByName("sphere") as Mesh<SphereGeometry, MeshBasicMaterial>;
        const sprite = endPoint.value.getObjectByName("sprite") as Sprite;
        // sphere.material.dispose();
        sprite.material.dispose();
        scene.remove(endPoint.value);
        endPoint.value = null;
        character.removeToScene();
        character.clearPath();
    }
};

const renderPointHelper = (point: Vector3) => {
    if (startPoint.value && endPoint.value) clearPointHelper();

    const group = new Group();
    group.userData.position = point;
    // const sphere = createSphere(.1, 0xff9900, point);
    const sprite = createImgSprite(
        coordinate_texture as Texture,
        point,
        0.15,
        0.02
    );
    // group.add(sphere);
    group.add(sprite);
    scene.add(group);
    if (startPoint.value) {
        endPoint.value = group;
        insideNavigation(props.floorId, startPoint.value.userData.position, endPoint.value.userData.position);
        console.log( startPoint.value.userData.position);
        console.log( endPoint.value.userData.position);
        
    } else {
        startPoint.value = group;
    }

};

// 室内导航方案（会初始化地图）
const insideNavigation = (zone: string, start_pos: Vector3, end_pos: Vector3) => {
    // controls.enabled = false;

    // character.setPathLineColor(`rgb(${getRandomIntInclusive(0, 255)}, ${getRandomIntInclusive(0, 255)}, ${getRandomIntInclusive(0, 255)})`);

    createPath(zone, start_pos, end_pos);
};
// 单地图两点间的导航路径（不会初始化地图）
const createPath = (zone: string, start_pos: Vector3, end_pos: Vector3) => {
    const path = path_finder.queryPath(zone, start_pos, end_pos);
    character.addToScene(start_pos);
    path.unshift(start_pos);
    character.setPath(path);
};
const handleMapClick = (point: Vector3) => {
    renderPointHelper(point);
};

renderer.setAnimationLoop(() => {
    const delta = clock.getDelta();
    renderer.render(scene, camera);
    if (cycle_light_texture) {
        cycle_light_texture.offset.x -= 0.005;
    }
    renderCSS2D(scene, camera);
});

defineExpose({
    startPoint,
    clearPointHelper,
    switch3D
});
</script>

<style scoped lang="scss">
.three-map {
    // border: 1px solid #ccc;
    overflow: hidden;
}
</style>
