import * as THREE from 'three';

let dustParticles = null;
let dustPositions = null;
let dustVelocities = null;
const DUST_COUNT = 600;

// Job Indicators
const _activeJobIndicators = new Map();
const INDICATOR_Y_OFFSET = 3.5; // Height above Timmy
const INDICATOR_X_OFFSET = 1.0; // Offset from Timmy's center for multiple jobs

const JOB_INDICATOR_DEFS = {
  writing: {
    create: () => {
      // Quill (cone for feather, cylinder for handle)
      const quillGroup = new THREE.Group();
      const featherGeo = new THREE.ConeGeometry(0.15, 0.6, 4);
      const featherMat = new THREE.MeshStandardMaterial({ color: 0xc8c4bc, roughness: 0.8 });
      const feather = new THREE.Mesh(featherGeo, featherMat);
      feather.position.y = 0.3;
      feather.rotation.x = Math.PI / 8;
      quillGroup.add(feather);

      const handleGeo = new THREE.CylinderGeometry(0.04, 0.04, 0.4, 8);
      const handleMat = new THREE.MeshStandardMaterial({ color: 0x3d2506, roughness: 0.7 });
      const handle = new THREE.Mesh(handleGeo, handleMat);
      handle.position.y = -0.2;
      quillGroup.add(handle);
      return quillGroup;
    },
    color: 0xe8d5a0, // parchment-like
  },
  coding: {
    create: () => {
      // Brackets (simple box geometry)
      const bracketsGroup = new THREE.Group();
      const bracketMat = new THREE.MeshStandardMaterial({ color: 0x5599dd, emissive: 0x224466, emissiveIntensity: 0.3, roughness: 0.4 });
      const bracketGeo = new THREE.BoxGeometry(0.05, 0.3, 0.05);

      const br1 = new THREE.Mesh(bracketGeo, bracketMat);
      br1.position.set(-0.1, 0.0, 0);
      bracketsGroup.add(br1);

      const br2 = br1.clone();
      br2.position.set(0.1, 0.0, 0);
      bracketsGroup.add(br2);

      const crossbarGeo = new THREE.BoxGeometry(0.25, 0.05, 0.05);
      const crossbar1 = new THREE.Mesh(crossbarGeo, bracketMat);
      crossbar1.position.set(0, 0.125, 0);
      bracketsGroup.add(crossbar1);

      const crossbar2 = crossbar1.clone();
      crossbar2.position.set(0, -0.125, 0);
      bracketsGroup.add(crossbar2);
      return bracketsGroup;
    },
    color: 0x5599dd, // code-editor blue
  },
  research: {
    create: () => {
      // Spider (simple sphere body, cylinder legs) - very simplified
      const spiderGroup = new THREE.Group();
      const bodyMat = new THREE.MeshStandardMaterial({ color: 0x444444, roughness: 0.9 });
      const body = new THREE.Mesh(new THREE.SphereGeometry(0.15, 8, 8), bodyMat);
      spiderGroup.add(body);

      const legMat = new THREE.MeshStandardMaterial({ color: 0x222222, roughness: 0.9 });
      const legGeo = new THREE.CylinderGeometry(0.015, 0.015, 0.4, 4);

      const legPositions = [
        [0.18, 0.0, 0.08, Math.PI / 4], [-0.18, 0.0, 0.08, -Math.PI / 4],
        [0.22, 0.0, -0.05, Math.PI / 2], [-0.22, 0.0, -0.05, -Math.PI / 2],
        [0.18, 0.0, -0.18, 3 * Math.PI / 4], [-0.18, 0.0, -0.18, -3 * Math.PI / 4],
      ];

      legPositions.forEach(([x, y, z, rotY]) => {
        const leg = new THREE.Mesh(legGeo, legMat);
        leg.position.set(x, y - 0.1, z);
        leg.rotation.z = Math.PI / 2;
        leg.rotation.y = rotY;
        spiderGroup.add(leg);
      });
      return spiderGroup;
    },
    color: 0x8b0000, // dark red, investigative
  },
  creative: {
    create: () => {
      // Lightbulb (sphere with small cylinder base)
      const bulbGroup = new THREE.Group();
      const bulbMat = new THREE.MeshStandardMaterial({ color: 0xffddaa, emissive: 0xffaa00, emissiveIntensity: 0.8, transparent: true, opacity: 0.9, roughness: 0.1 });
      const bulb = new THREE.Mesh(new THREE.SphereGeometry(0.2, 16, 12), bulbMat);
      bulbGroup.add(bulb);

      const baseMat = new THREE.MeshStandardMaterial({ color: 0x888888, roughness: 0.6 });
      const base = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.1, 0.15, 8), baseMat);
      base.position.y = -0.25;
      bulbGroup.add(base);
      return bulbGroup;
    },
    color: 0xffaa00, // bright idea yellow
  },
  analysis: {
    create: () => {
      // Magnifying glass (torus for rim, plane for lens)
      const magGroup = new THREE.Group();
      const rimMat = new THREE.MeshStandardMaterial({ color: 0xbb9900, roughness: 0.4, metalness: 0.7 });
      const rim = new THREE.Mesh(new THREE.TorusGeometry(0.2, 0.03, 8, 20), rimMat);
      magGroup.add(rim);

      const handleMat = new THREE.MeshStandardMaterial({ color: 0x3d2506, roughness: 0.7 });
      const handle = new THREE.Mesh(new THREE.CylinderGeometry(0.03, 0.03, 0.4, 6), handleMat);
      handle.position.set(0.25, -0.25, 0);
      handle.rotation.z = Math.PI / 4;
      magGroup.add(handle);

      const lensMat = new THREE.MeshPhysicalMaterial({ color: 0xaaffff, transmission: 0.8, roughness: 0.1, transparent: true });
      const lens = new THREE.Mesh(new THREE.CircleGeometry(0.17, 16), lensMat);
      // Lens is a plane, so it will be rotated to face the camera or just set its position
      // For simplicity, make it a thin cylinder or sphere segment to give it depth
      const lensGeo = new THREE.CylinderGeometry(0.17, 0.17, 0.02, 16);
      const thinLens = new THREE.Mesh(lensGeo, lensMat);
      magGroup.add(thinLens);

      return magGroup;
    },
    color: 0x88ddff, // clear blue, analytic
  },
  other: { // Generic glowing orb
    create: () => {
      const orbMat = new THREE.MeshStandardMaterial({ color: 0x800080, emissive: 0x550055, emissiveIntensity: 0.8, roughness: 0.2 });
      return new THREE.Mesh(new THREE.SphereGeometry(0.2, 16, 16), orbMat);
    },
    color: 0x800080, // purple
  },
};

export function initEffects(scene) {
  initDustMotes(scene);
}

// Map to hold job indicator objects by jobId
const jobIndicators = new Map();

export function createJobIndicator(category, jobId, position) {
  const def = JOB_INDICATOR_DEFS[category] || JOB_INDICATOR_DEFS.other;
  const indicatorGroup = new THREE.Group();
  indicatorGroup.userData.jobId = jobId;
  indicatorGroup.userData.category = category;

  const object = def.create();
  object.scale.setScalar(0.7); // Make indicators a bit smaller
  indicatorGroup.add(object);

  // Add a subtle glowing point light to the indicator
  const pointLight = new THREE.PointLight(def.color, 0.8, 3);
  indicatorGroup.add(pointLight);

  indicatorGroup.position.copy(position);

  jobIndicators.set(jobId, indicatorGroup);
  return indicatorGroup;
}

export function updateJobIndicators(time) {
  const t = time * 0.001;
  jobIndicators.forEach(indicator => {
    // Simple bobbing motion
    indicator.position.y += Math.sin(t * 2.5 + indicator.userData.jobId.charCodeAt(0)) * 0.002;
    // Rotation
    indicator.rotation.y += 0.01;
  });
}

export function dissolveJobIndicator(jobId, scene) {
  const indicator = jobIndicators.get(jobId);
  if (indicator) {
    // TODO: Implement particle dissolve effect here
    // For now, just remove and dispose
    scene.remove(indicator);
    if (indicator.children.length > 0) {
      const object = indicator.children[0];
      if (object.geometry) object.geometry.dispose();
      if (object.material) {
        if (Array.isArray(object.material)) object.material.forEach(m => m.dispose());
        else object.material.dispose();
      }
    }
    indicator.children.forEach(child => {
        if (child.isLight) child.dispose();
    });
    jobIndicators.delete(jobId);
  }
}

function initDustMotes(scene) {
  const geo = new THREE.BufferGeometry();
  const positions = new Float32Array(DUST_COUNT * 3);
  const colors = new Float32Array(DUST_COUNT * 3);
  const velocities = new Float32Array(DUST_COUNT);

  for (let i = 0; i < DUST_COUNT; i++) {
    positions[i * 3]     = (Math.random() - 0.5) * 22;
    positions[i * 3 + 1] = Math.random() * 10;
    positions[i * 3 + 2] = (Math.random() - 0.5) * 16 - 2;
    velocities[i]         = 0.008 + Math.random() * 0.012;

    const roll = Math.random();
    if (roll < 0.6) {
      colors[i * 3] = 0.9 + Math.random() * 0.1;
      colors[i * 3 + 1] = 0.7 + Math.random() * 0.2;
      colors[i * 3 + 2] = 0.3 + Math.random() * 0.3;
    } else {
      const b = 0.3 + Math.random() * 0.5;
      colors[i * 3] = 0;
      colors[i * 3 + 1] = b;
      colors[i * 3 + 2] = 0;
    }
  }

  geo.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  geo.setAttribute('color', new THREE.BufferAttribute(colors, 3));
  dustPositions = positions;
  dustVelocities = velocities;

  const mat = new THREE.PointsMaterial({
    size: 0.06,
    vertexColors: true,
    transparent: true,
    opacity: 0.55,
    sizeAttenuation: true,
  });

  dustParticles = new THREE.Points(geo, mat);
  scene.add(dustParticles);
}

export function updateEffects(time) {
  if (!dustParticles) return;
  const t = time * 0.001;

  for (let i = 0; i < DUST_COUNT; i++) {
    dustPositions[i * 3 + 1] += dustVelocities[i];
    dustPositions[i * 3]     += Math.sin(t * 0.5 + i * 0.1) * 0.002;

    if (dustPositions[i * 3 + 1] > 10) {
      dustPositions[i * 3 + 1] = 0;
      dustPositions[i * 3]     = (Math.random() - 0.5) * 22;
      dustPositions[i * 3 + 2] = (Math.random() - 0.5) * 16 - 2;
    }
  }
  dustParticles.geometry.attributes.position.needsUpdate = true;
}

export function disposeEffects() {
  if (dustParticles) {
    dustParticles.geometry.dispose();
    dustParticles.material.dispose();
    dustParticles = null;
  }
  dustPositions = null;
  dustVelocities = null;
  jobIndicators.forEach(indicator => {
    if (indicator.children.length > 0) {
      const object = indicator.children[0];
      if (object.geometry) object.geometry.dispose();
      if (object.material) {
        if (Array.isArray(object.material)) object.material.forEach(m => m.dispose());
        else object.material.dispose();
      }
    }
    indicator.children.forEach(child => {
        if (child.isLight) child.dispose();
    });
  });
  jobIndicators.clear();
}