import * as THREE from 'three';
import { state } from '../state.js';

const SPIDER_COUNT = 5;
const SPIDER_SPEED = 0.0001;
const SPIDER_TURN_SPEED = 0.02;
const SPIDER_WAIT_MIN = 200; // frames
const SPIDER_WAIT_MAX = 500; // frames

export class SpiderEffect {
    constructor(scene) {
        this.spiders = [];
        this._setupSpiders(scene);
    }

    _getRandomPointOnWall(wall) {
        const position = new THREE.Vector3();
        const width = wall.geometry.parameters.width;
        const height = wall.geometry.parameters.height;

        position.x = (Math.random() - 0.5) * width;
        position.y = (Math.random() - 0.5) * height;
        position.z = 0; // Local z is 0 for a plane

        // Convert local position to world position
        return wall.localToWorld(position);
    }

    _createSpiderMesh() {
        const spiderGroup = new THREE.Group();
        const spiderMaterial = new THREE.MeshPhongMaterial({ color: 0x919191, shininess: 50 });

        // Body
        const bodyGeometry = new THREE.SphereGeometry(0.01, 6, 5);
        const body = new THREE.Mesh(bodyGeometry, spiderMaterial);
        body.scale.z = 0.6; // Flatten the sphere
        body.castShadow = true;
        spiderGroup.add(body);

        // Head
        const headGeometry = new THREE.SphereGeometry(0.005, 5, 4);
        const head = new THREE.Mesh(headGeometry, spiderMaterial);
        head.position.y = 0.015;
        head.castShadow = true;
        spiderGroup.add(head);

        spiderGroup.userData = {
            state: 'crawling', // 'crawling', 'waiting'
            waitTimer: 0,
            t: 0,
            curve: null,
            currentWall: null,
        };

        return spiderGroup;
    }

    _findNewTarget(spider) {
        if (!spider.userData.currentWall) {
            // First time, pick a random wall
            const walls = state.crawlSurfaces;
            if (walls.length === 0) return;
            spider.userData.currentWall = walls[Math.floor(Math.random() * walls.length)];
            spider.position.copy(this._getRandomPointOnWall(spider.userData.currentWall));
        }

        const startPoint = spider.position.clone();
        const endPoint = this._getRandomPointOnWall(spider.userData.currentWall);

        // Create a curved path on the wall
        const midPoint = new THREE.Vector3().lerpVectors(startPoint, endPoint, 0.5);
        const direction = new THREE.Vector3().subVectors(endPoint, startPoint).normalize();
        const wallNormal = spider.userData.currentWall.getWorldDirection(new THREE.Vector3()).negate();
        
        // Get a perpendicular vector on the plane of the wall
        const perpendicular = new THREE.Vector3().crossVectors(direction, wallNormal).normalize();
        const offsetMagnitude = startPoint.distanceTo(endPoint) * (Math.random() * 0.4 - 0.2); // Random offset left or right
        
        const controlPoint = midPoint.clone().add(perpendicular.multiplyScalar(offsetMagnitude));

        spider.userData.curve = new THREE.QuadraticBezierCurve3(startPoint, controlPoint, endPoint);
        spider.userData.t = 0;
        spider.userData.state = 'crawling';
    }

    _setupSpiders(scene) {
        for (let i = 0; i < SPIDER_COUNT; i++) {
            const spider = this._createSpiderMesh();
            scene.add(spider);
            this.spiders.push(spider);
            this._findNewTarget(spider); // Initial placement
        }
    }

    update() {
        this.spiders.forEach(spider => {
            const data = spider.userData;

            if (data.state === 'crawling') {
                if (!data.curve) {
                    this._findNewTarget(spider);
                    return;
                }

                data.t += SPIDER_SPEED;
                if (data.t >= 1) {
                    spider.position.copy(data.curve.v2);
                    data.state = 'waiting';
                    data.waitTimer = SPIDER_WAIT_MIN + Math.random() * (SPIDER_WAIT_MAX - SPIDER_WAIT_MIN);
                } else {
                    spider.position.copy(data.curve.getPoint(data.t));
                    
                    // Smoothly turn the spider towards the tangent of the curve
                    const tangent = data.curve.getTangent(data.t);
                    const up = data.currentWall.getWorldDirection(new THREE.Vector3()).negate();
                    
                    const targetQuaternion = new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 1, 0), tangent).multiply(
                        new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 0, 1), up)
                    );

                    spider.quaternion.slerp(targetQuaternion, SPIDER_TURN_SPEED);
                }
            } else if (data.state === 'waiting') {
                data.waitTimer--;
                if (data.waitTimer <= 0) {
                    this._findNewTarget(spider);
                }
            }
        });
    }
}