import * as THREE from 'three';
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
import { useSimulation } from '../useSimulation';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

export function useInteraction(
    camera: THREE.Camera,
    renderer: THREE.WebGLRenderer,
    scene: THREE.Scene,
    interactableObjects: THREE.Object3D[],
    getControls: () => OrbitControls
) {
    const { selectedBuilding, loadBuildingData } = useSimulation();

    let raycaster: THREE.Raycaster;
    let mouse: THREE.Vector2;
    let transformControls: TransformControls;
    let selectionRing: THREE.Mesh;
    let transformEnabled = false;

    const initSelectionRing = () => {
        // Use a base 1x1 square for easy scaling
        const geometry = new THREE.PlaneGeometry(1, 1);
        const material = new THREE.MeshBasicMaterial({ color: 0xffff00, side: THREE.DoubleSide, transparent: true, opacity: 0.5 });
        // Instead of a solid plane, let's use a thick border? 
        // Or stick to RingGeometry but configured as a square aligned to axes?
        // Actually, EdgesGeometry is cleaner for a "line".
        // But user liked the "square" (maybe filled or thick?). 
        // The previous one was RingGeometry(6, 7, 4) -> thick band.

        // Let's create a dynamic mesh that is essentially a border. 
        // We can just use a helper or scale a Ring?
        // Let's try scaling a simple Plane with a texture? No texture tool.

        // Let's use a BoxHelper style logic but with a thick transparent mesh.
        // We will create a RING that is 1x1.
        // RingGeometry(0.8, 1, 4) rotated 45deg is a square frame.
        // But scaling a rotated frame is hard.

        // Let's use a Group with 4 scaled cubes? No.

        // Simplest: A PlaneGeometry(1,1) that is solid but transparent yellow (highlight).
        // Plus a LineSegments(EdgesGeometry) for border.

        // User asked for "highlighting square". The previous one was a ring. 
        // Let's go with a transparent Plane slightly larger than building.

        selectionRing = new THREE.Mesh(geometry, material);
        selectionRing.rotation.x = -Math.PI / 2;
        selectionRing.visible = false;

        // Add a border line
        const edges = new THREE.EdgesGeometry(geometry);
        const line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ color: 0xffff00 }));
        selectionRing.add(line);

        scene.add(selectionRing);
    };

    let selectedMesh: THREE.Mesh | null = null;
    let originalMaterial: THREE.Material | THREE.Material[] | null = null;

    const clearSelectionHighlight = () => {
        if (selectedMesh && originalMaterial) {
            // Dispose the cloned material to avoid memory leaks
            if (Array.isArray(selectedMesh.material)) {
                selectedMesh.material.forEach(m => m.dispose());
            } else {
                selectedMesh.material.dispose();
            }
            // Restore original
            selectedMesh.material = originalMaterial;
        }
        selectedMesh = null;
        originalMaterial = null;
    };

    const applySelectionHighlight = (mesh: THREE.Mesh) => {
        clearSelectionHighlight(); // Clear previous

        selectedMesh = mesh;
        if (Array.isArray(mesh.material)) {
            originalMaterial = mesh.material;
            // Clone isn't straightforward for array, skip for now or we could map clone
        } else {
            originalMaterial = mesh.material;
            const newMat = mesh.material.clone();
            if ('emissive' in newMat) {
                (newMat as THREE.MeshStandardMaterial).emissive.setHex(0x555555);
            }
            mesh.material = newMat;
        }
    };

    const updateSelectionRing = (target: THREE.Object3D) => {
        if (!target) {
            selectionRing.visible = false;
            return;
        }

        // Provide visual feedback
        selectionRing.visible = true;

        // Calculate Bounds
        const box = new THREE.Box3().setFromObject(target);
        const size = new THREE.Vector3();
        box.getSize(size);

        const padding = 2; // Reduced padding for tighter fit
        selectionRing.scale.set(size.x + padding, size.z + padding, 1);

        selectionRing.position.copy(target.position);
        selectionRing.position.y = 0.6; // Raised above grass (0.5)
    };

    const initInteraction = () => {
        raycaster = new THREE.Raycaster();
        mouse = new THREE.Vector2();

        initSelectionRing();

        // Transform Controls
        transformControls = new TransformControls(camera, renderer.domElement);
        transformControls.setMode('translate');
        transformControls.showY = false;
        transformControls.enabled = false;

        transformControls.addEventListener('dragging-changed', (event) => {
            const controls = getControls();
            if (controls) controls.enabled = !event.value;
        });

        try {
            scene.add(transformControls.getHelper());
        } catch (e) {
            console.error("Failed to add TransformControls helper to scene:", e);
        }

        window.addEventListener('keydown', (event) => {
            if (event.key === 'm') {
                transformEnabled = !transformEnabled;
                transformControls.enabled = transformEnabled;
                if (!transformEnabled) {
                    transformControls.detach();
                }
                console.log("Move Mode:", transformEnabled ? "ON" : "OFF");
            }
        });

        renderer.domElement.addEventListener('pointerdown', onPointerDown);
        renderer.domElement.addEventListener('pointerup', onPointerUp);
    };

    let startX = 0;
    let startY = 0;

    const onPointerDown = (event: MouseEvent) => {
        startX = event.clientX;
        startY = event.clientY;
    };

    const onPointerUp = (event: MouseEvent) => {
        const diffX = Math.abs(event.clientX - startX);
        const diffY = Math.abs(event.clientY - startY);

        // Click Threshold (pixels)
        if (diffX > 5 || diffY > 5) {
            return; // Dragged, ignore
        }

        const rect = renderer.domElement.getBoundingClientRect();
        mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
        mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

        raycaster.setFromCamera(mouse, camera);
        const intersects = raycaster.intersectObjects(interactableObjects);

        // Move Mode
        if (transformEnabled) {
            if (intersects.length > 0) {
                const object = intersects[0].object;
                const group = object.userData.parentGroup || object;
                transformControls.attach(group);
            } else {
                transformControls.detach();
            }
        }

        // Selection Mode
        if (intersects.length > 0) {
            const object = intersects[0].object;
            const group = object.userData.parentGroup || object;

            const data = group.userData;

            // Highlight Mesh
            if (group instanceof THREE.Mesh) {
                applySelectionHighlight(group);
            }

            // Screen coords for Info Window
            const vector = group.position.clone();
            vector.project(camera);
            const x = (vector.x * .5 + .5) * rect.width;
            const y = (-(vector.y * .5) + .5) * rect.height;

            selectedBuilding.value = {
                id: data.id,
                type: data.type,
                description: data.description,
                consumption: data.consumption || 'Loading...',
                generation: data.generation || 'Loading...',
                iot: data.iot || 'None',
                csvPath: data.csvPath,
                uiX: x,
                uiY: y
            };

            if (data.csvPath) {
                loadBuildingData(data.id, data.csvPath).then((rows: any) => {
                    if (selectedBuilding.value && selectedBuilding.value.id === data.id) {
                        if (rows && rows.length > 0) {
                            const row = rows[0];
                            selectedBuilding.value.consumption = row.Consumption;
                            selectedBuilding.value.generation = row.Generation;
                        }
                    }
                });
            }
            updateSelectionRing(group);
        } else {
            // Only Deselect if we clicked on NOTHING, and we weren't dragging.
            selectedBuilding.value = null;
            clearSelectionHighlight();
            updateSelectionRing(null as any);
        }
    };

    return {
        initInteraction
    };
}
