/**
 * Pip the Familiar — a small glowing orb that floats around the room.
 *
 * Emerald green core with a gold particle trail.
 * Wanders on a randomized path, occasionally pauses near Timmy.
 */

import * as THREE from "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js";

const CORE_COLOR = 0x00b450;
const GLOW_COLOR = 0x00b450;
const TRAIL_COLOR = 0xdaa520;

/**
 * Create the familiar and return { group, update }.
 * Call update(dt) each frame.
 */
export function createFamiliar() {
    const group = new THREE.Group();

    // --- Core orb ---
    const coreGeo = new THREE.SphereGeometry(0.08, 12, 10);
    const coreMat = new THREE.MeshStandardMaterial({
        color: CORE_COLOR,
        emissive: GLOW_COLOR,
        emissiveIntensity: 1.5,
        roughness: 0.2,
    });
    const core = new THREE.Mesh(coreGeo, coreMat);
    group.add(core);

    // --- Glow (larger transparent sphere) ---
    const glowGeo = new THREE.SphereGeometry(0.15, 10, 8);
    const glowMat = new THREE.MeshBasicMaterial({
        color: GLOW_COLOR,
        transparent: true,
        opacity: 0.15,
    });
    const glow = new THREE.Mesh(glowGeo, glowMat);
    group.add(glow);

    // --- Point light from Pip ---
    const light = new THREE.PointLight(CORE_COLOR, 0.4, 4);
    group.add(light);

    // --- Trail particles (simple small spheres) ---
    const trailCount = 6;
    const trails = [];
    const trailGeo = new THREE.SphereGeometry(0.02, 4, 4);
    const trailMat = new THREE.MeshBasicMaterial({
        color: TRAIL_COLOR,
        transparent: true,
        opacity: 0.6,
    });
    for (let i = 0; i < trailCount; i++) {
        const t = new THREE.Mesh(trailGeo, trailMat.clone());
        t.visible = false;
        group.add(t);
        trails.push({ mesh: t, age: 0, maxAge: 0.3 + Math.random() * 0.3 });
    }

    // Starting position
    group.position.set(1.5, 1.8, -0.5);

    // Wandering state
    let elapsed = 0;
    let trailTimer = 0;
    let trailIndex = 0;

    // Waypoints for random wandering
    const waypoints = [
        new THREE.Vector3(1.5, 1.8, -0.5),
        new THREE.Vector3(-1.0, 2.0, 0.5),
        new THREE.Vector3(0.0, 1.5, -0.3),  // near Timmy
        new THREE.Vector3(1.2, 2.2, 0.8),
        new THREE.Vector3(-0.5, 1.3, -0.2),  // near desk
        new THREE.Vector3(0.3, 2.5, 0.3),
    ];
    let waypointIndex = 0;
    let target = waypoints[0].clone();
    let pauseTimer = 0;

    function pickNextTarget() {
        waypointIndex = (waypointIndex + 1) % waypoints.length;
        target.copy(waypoints[waypointIndex]);
        // Add randomness
        target.x += (Math.random() - 0.5) * 0.6;
        target.y += (Math.random() - 0.5) * 0.3;
        target.z += (Math.random() - 0.5) * 0.6;
    }

    function update(dt) {
        elapsed += dt;

        // Move toward target
        if (pauseTimer > 0) {
            pauseTimer -= dt;
        } else {
            const dir = target.clone().sub(group.position);
            const dist = dir.length();
            if (dist < 0.15) {
                pickNextTarget();
                // Occasionally pause
                if (Math.random() < 0.3) {
                    pauseTimer = 1.0 + Math.random() * 2.0;
                }
            } else {
                dir.normalize();
                const speed = 0.4;
                group.position.add(dir.multiplyScalar(speed * dt));
            }
        }

        // Bob up and down
        group.position.y += Math.sin(elapsed * 3.0) * 0.002;

        // Pulse glow
        const pulse = 0.12 + Math.sin(elapsed * 4.0) * 0.05;
        glowMat.opacity = pulse;
        coreMat.emissiveIntensity = 1.2 + Math.sin(elapsed * 3.5) * 0.4;

        // Trail particles
        trailTimer += dt;
        if (trailTimer > 0.1) {
            trailTimer = 0;
            const t = trails[trailIndex];
            t.mesh.position.copy(group.position);
            t.mesh.position.x += (Math.random() - 0.5) * 0.1;
            t.mesh.position.y += (Math.random() - 0.5) * 0.1;
            t.mesh.visible = true;
            t.age = 0;
            // Convert to local space
            group.worldToLocal(t.mesh.position);
            trailIndex = (trailIndex + 1) % trailCount;
        }

        // Age and fade trail particles
        for (const t of trails) {
            if (!t.mesh.visible) continue;
            t.age += dt;
            if (t.age >= t.maxAge) {
                t.mesh.visible = false;
            } else {
                t.mesh.material.opacity = 0.6 * (1.0 - t.age / t.maxAge);
            }
        }
    }

    return { group, update };
}
