import * as THREE from "three";
import gsap from "gsap";
import * as Types from "../../../../types/world/worldTypes";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { initializeDB, retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils";
import * as CONSTANTS from '../../../../types/world/worldConstants';
import { toast } from 'react-toastify';

let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
let currentTaskId = 0; // Track the active task
let activePromises = new Map<number, boolean>(); // Map to track task progress

export default async function assetManager(
    data: any,
    itemsGroup: Types.RefGroup,
    loader: GLTFLoader,
) {
    const taskId = ++currentTaskId; // Increment taskId for each call
    activePromises.set(taskId, true); // Mark task as active

    // console.log("Received message from worker:", data);

    if (data.toRemove.length > 0) {
        data.toRemove.forEach((uuid: string) => {
            const item = itemsGroup.current.getObjectByProperty("uuid", uuid);
            if (item) {
                // Traverse and dispose of resources
                // item.traverse((child: THREE.Object3D) => {
                //     if (child instanceof THREE.Mesh) {
                //         if (child.geometry) child.geometry.dispose();
                //         if (Array.isArray(child.material)) {
                //             child.material.forEach((material) => {
                //                 if (material.map) material.map.dispose();
                //                 material.dispose();
                //             });
                //         } else if (child.material) {
                //             if (child.material.map) child.material.map.dispose();
                //             child.material.dispose();
                //         }
                //     }
                // });

                // Remove the object from the scene
                itemsGroup.current.remove(item);
            }
        });
    }

    if (data.toAdd.length > 0) {
        await initializeDB();

        for (const item of data.toAdd) {
            if (!activePromises.get(taskId)) return; // Stop processing if task is canceled

            await new Promise<void>(async (resolve) => {
                const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`;

                // Check Three.js Cache
                const cachedModel = THREE.Cache.get(item.modelfileID!);
                if (cachedModel) {
                    // console.log(`[Cache] Fetching ${item.modelname}`);
                    processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, resolve);
                    return;
                }

                // Check IndexedDB
                const indexedDBModel = await retrieveGLTF(item.modelfileID!);
                if (indexedDBModel) {
                    // console.log(`[IndexedDB] Fetching ${item.modelname}`);
                    const blobUrl = URL.createObjectURL(indexedDBModel);
                    loader.load(
                        blobUrl,
                        (gltf) => {
                            URL.revokeObjectURL(blobUrl);
                            THREE.Cache.remove(blobUrl);
                            THREE.Cache.add(item.modelfileID!, gltf); // Add to cache
                            processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve);
                        },
                        undefined,
                        (error) => {
                            toast.error(`[IndexedDB] Error loading ${item.modelname}:`);
                            resolve();
                        }
                    );
                    return;
                }

                // Fetch from Backend
                // console.log(`[Backend] Fetching ${item.modelname}`);
                loader.load(
                    modelUrl,
                    async (gltf) => {
                        const modelBlob = await fetch(modelUrl).then((res) => res.blob());
                        await storeGLTF(item.modelfileID!, modelBlob); // Store in IndexedDB
                        THREE.Cache.add(item.modelfileID!, gltf); // Add to cache
                        processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve);
                    },
                    undefined,
                    (error) => {
                        toast.error(`[Backend] Error loading ${item.modelname}:`);
                        resolve();
                    }
                );
            });
        }

        function processLoadedModel(
            gltf: any,
            item: Types.FloorItemType,
            itemsGroup: Types.RefGroup,
            resolve: () => void
        ) {
            if (!activePromises.get(taskId)) return; // Stop processing if task is canceled

            const existingModel = itemsGroup?.current?.getObjectByProperty("uuid", item.modeluuid);
            if (existingModel) {
                // console.log(`Model ${item.modelname} already exists in the scene.`);
                resolve();
                return;
            }

            const model = gltf;
            model.uuid = item.modeluuid;
            model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid };
            model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
            model.position.set(...item.position);
            model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);

            model.traverse((child: any) => {
                if (child.isMesh) {
                    // Clone the material to ensure changes are independent
                    // child.material = child.material.clone();

                    child.castShadow = true;
                    child.receiveShadow = true;
                }
            });


            itemsGroup?.current?.add(model);

            gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: "power2.out" });
            gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 0.5, ease: "power2.out", onStart: resolve, });
        }
    }

    activePromises.delete(taskId); // Mark task as complete
}

// Cancel ongoing task when new call arrives
export function cancelOngoingTasks() {
    activePromises.clear(); // Clear all ongoing tasks
}
