import * as THREE from 'three';
import type { Game } from './Game';
import { Enemy } from './Enemy';

const BEE_COUNT = 4;

interface SwarmBee {
  mesh: THREE.Group;
  wingL: THREE.Mesh;
  wingR: THREE.Mesh;
  angle: number;
  radius: number;
  orbitSpeed: number;
  scatter: THREE.Vector3;
}

export class BeeSwarm extends Enemy {
  private model: THREE.Group;
  private bees: SwarmBee[] = [];
  private time = Math.random() * Math.PI * 2;

  constructor() {
    super();
    this.health = 50;
    this.speed = 6.5;
    this.xp = 15;

    this.model = new THREE.Group();
    this.body.add(this.model);

    const bodyGeom = new THREE.CapsuleGeometry(0.11, 0.16, 4, 10);
    const bodyMat = new THREE.MeshToonMaterial({ color: 0xffcc33 });
    const stripeMat = new THREE.MeshToonMaterial({ color: 0x222222 });
    const wingMat = new THREE.MeshToonMaterial({
      color: 0xffffff,
      transparent: true,
      opacity: 0.7,
      side: THREE.DoubleSide,
    });

    for (let i = 0; i < BEE_COUNT; i++) {
      const bee = new THREE.Group();

      const body = new THREE.Mesh(bodyGeom, bodyMat);
      body.rotation.x = Math.PI / 2;
      bee.add(body);

      for (const stripeZ of [-0.1, 0.1]) {
        const stripe = new THREE.Mesh(new THREE.CylinderGeometry(0.115, 0.115, 0.05, 10), stripeMat);
        stripe.rotation.x = Math.PI / 2;
        stripe.position.z = stripeZ;
        bee.add(stripe);
      }

      const wingL = new THREE.Mesh(new THREE.PlaneGeometry(0.14, 0.24), wingMat);
      wingL.position.set(0.12, 0.08, -0.02);
      wingL.rotation.y = Math.PI / 2;
      bee.add(wingL);
      const wingR = wingL.clone();
      wingR.position.x = -0.12;
      bee.add(wingR);

      bee.scale.setScalar(0.9);
      this.model.add(bee);
      this.bees.push({
        mesh: bee,
        wingL,
        wingR,
        angle: (i / BEE_COUNT) * Math.PI * 2,
        radius: 0.4 + (i % 2) * 0.15,
        orbitSpeed: 2 + (i % 3) * 0.4,
        scatter: new THREE.Vector3(
          Math.cos((i / BEE_COUNT) * Math.PI * 2),
          0.5 + Math.random(),
          Math.sin((i / BEE_COUNT) * Math.PI * 2)
        ).multiplyScalar(3),
      });
    }

    this.fadeOutModel = this.model;
  }

  playAnim() {
    // Procedural visuals only
  }

  updateAnimation(dt: number) {
    if (this.dead) {
      // Scatter the bees outward while fading
      this.time += dt;
      for (const bee of this.bees) {
        bee.mesh.position.x += bee.scatter.x * dt;
        bee.mesh.position.y += bee.scatter.y * dt;
        bee.mesh.position.z += bee.scatter.z * dt;
      }
      this.updateFadeDeath(dt, { duration: 1.0, shrink: 0.4 });
    }
  }

  update(dt: number, game: Game) {
    this.time += dt;
    this.body.position.y = 1.2 + Math.sin(this.time * 2) * 0.2;

    // Orbit the individual bees around the cluster center
    for (const bee of this.bees) {
      bee.angle += bee.orbitSpeed * dt;
      bee.mesh.position.set(
        Math.cos(bee.angle) * bee.radius,
        Math.sin(bee.angle * 2.3) * 0.25,
        Math.sin(bee.angle) * bee.radius
      );
      bee.mesh.rotation.y = -bee.angle;
      const flap = Math.sin(this.time * 40 + bee.angle) * 0.9;
      bee.wingL.rotation.x = flap;
      bee.wingR.rotation.x = -flap;
    }

    const toPlayer = new THREE.Vector3()
      .subVectors(game.player.body.position, this.body.position);
    toPlayer.y = 0;
    const dist = toPlayer.length();
    if (dist > 0.1) {
      const dir = toPlayer.normalize();
      this.body.lookAt(
        this.body.position.x + dir.x,
        this.body.position.y,
        this.body.position.z + dir.z
      );
      const perp = new THREE.Vector3(-dir.z, 0, dir.x)
        .multiplyScalar(Math.sin(this.time * 4) * 0.8);

      let moveDir = dir.clone().multiplyScalar(this.speed).add(perp);
      if (this.knockback > 0) {
        moveDir = dir.multiplyScalar(-this.speed);
        this.knockback -= dt;
      }
      this.body.position.x += moveDir.x * dt;
      this.body.position.z += moveDir.z * dt;
      game.clampToArena(this.body.position);
    }
  }

  protected onDeath(_game: Game) {
    this.beginFadeDeath();
  }
}
