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

const IDLE_DIST_MIN = 7;
const IDLE_DIST_MAX = 11;
const SPORE_COOLDOWN = 3;
const SPORE_SPEED = 5;
const SPORE_HOMING = 1.6;
const SPORE_DAMAGE = 8;
const SPORE_SLOW = 1.5;
const SPORE_HIT_RADIUS = 1.0;
const SPORE_LIFE = 4;
const FLOAT_HEIGHT = 1.2;
const HIT_FLASH_TIME = 0.14;

// Irrlicht: schwebender Caster, schießt langsame Homing-Sporen (Slow)
export class Wisp extends Enemy {
  private model: THREE.Group;
  private glowMat!: THREE.MeshBasicMaterial;
  private coreMat!: THREE.MeshToonMaterial;
  private tailMat!: THREE.MeshBasicMaterial;
  private tail!: THREE.Mesh;
  private shadow!: THREE.Mesh;
  private shadowMat!: THREE.MeshBasicMaterial;
  private sporeTimer = 1.5 + Math.random();
  private time = Math.random() * Math.PI * 2;
  private hitFlash = 0;
  private spores: WispSpore[] = [];

  constructor() {
    super();
    this.health = 35;
    this.speed = 3.8;
    this.xp = 18;
    this.contactDps = 8;
    this.contactRadius = 1.6;

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

    this.glowMat = new THREE.MeshBasicMaterial({
      color: 0xaaffcc,
      transparent: true,
      opacity: 0.55,
      blending: THREE.AdditiveBlending,
      depthWrite: false,
    });
    const glow = new THREE.Mesh(new THREE.SphereGeometry(0.45, 12, 10), this.glowMat);
    this.model.add(glow);

    this.coreMat = new THREE.MeshToonMaterial({ color: 0x66ffaa, emissive: 0x114422 });
    const core = new THREE.Mesh(new THREE.SphereGeometry(0.28, 10, 8), this.coreMat);
    this.model.add(core);

    // Schweif (verjüngter Kegel, wackelt)
    this.tailMat = new THREE.MeshBasicMaterial({
      color: 0x88ffbb,
      transparent: true,
      opacity: 0.4,
      blending: THREE.AdditiveBlending,
      depthWrite: false,
    });
    this.tail = new THREE.Mesh(new THREE.ConeGeometry(0.12, 0.7, 6), this.tailMat);
    this.tail.rotation.x = Math.PI / 2;
    this.tail.position.set(0, 0, -0.55);
    this.model.add(this.tail);

    // Boden-Schatten
    this.shadowMat = new THREE.MeshBasicMaterial({
      color: 0x000000,
      transparent: true,
      opacity: 0.22,
    });
    this.shadow = new THREE.Mesh(new THREE.CircleGeometry(0.4, 16), this.shadowMat);
    this.shadow.rotation.x = -Math.PI / 2;
    this.shadow.renderOrder = 998;
    this.body.add(this.shadow);
  }

  playAnim() {
    // Prozedurale Optik
  }

  updateAnimation(dt: number) {
    this.updateFadeDeath(dt, { duration: 0.8, shrink: 0.7 });
  }

  update(dt: number, game: Game) {
    this.time += dt;

    // Schweben + Pulsieren
    this.body.position.y = FLOAT_HEIGHT + Math.sin(this.time * 2.4) * 0.25;
    this.shadow.position.y = 0.06 - this.body.position.y;
    const pulse = 1 + Math.sin(this.time * 5) * 0.15;
    this.model.scale.setScalar(pulse);
    this.glowMat.opacity = 0.4 + Math.abs(Math.sin(this.time * 5)) * 0.2;
    this.tail.rotation.z = Math.sin(this.time * 3) * 0.3;

    // Hit-Feedback
    if (this.hitFlash > 0) {
      this.hitFlash -= dt;
      this.coreMat.color.set(0xffffff);
    } else {
      this.coreMat.color.set(0x66ffaa);
    }

    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
      );

      // Abstand halten: schwebt in mittlerer Reichweite
      let move = new THREE.Vector3();
      if (dist < IDLE_DIST_MIN) {
        move.copy(dir).multiplyScalar(-1);
      } else if (dist > IDLE_DIST_MAX) {
        move.copy(dir);
      }
      if (this.knockback > 0) {
        move = dir.clone().multiplyScalar(-1);
        this.knockback -= dt;
      }
      if (move.lengthSq() > 0) {
        move.normalize().multiplyScalar(this.speed);
        this.body.position.x += move.x * dt;
        this.body.position.z += move.z * dt;
        game.clampToArena(this.body.position);
      }
    }

    // Spore schießen
    this.sporeTimer -= dt;
    if (this.sporeTimer <= 0 && game.player.health > 0) {
      this.sporeTimer = SPORE_COOLDOWN + Math.random() * 0.5;
      const from = new THREE.Vector3(this.body.position.x, this.body.position.y, this.body.position.z);
      const spore = new WispSpore(from);
      game.scene.add(spore.body);
      this.spores.push(spore);
      playSound('spawn', 0.35);
    }

    // Sporen aktualisieren
    for (let i = this.spores.length - 1; i >= 0; i--) {
      if (!this.spores[i].update(dt, game)) {
        this.spores[i].dispose();
        this.spores.splice(i, 1);
      }
    }
  }

  override takeDamage(
    damage: number,
    game: Game,
    withKnockback = true,
    sourcePos?: THREE.Vector3
  ) {
    super.takeDamage(damage, game, withKnockback, sourcePos);
    this.hitFlash = HIT_FLASH_TIME;
  }

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

  override dispose() {
    super.dispose();
    this.cleanupSpores();
  }

  private cleanupSpores() {
    for (const s of this.spores) s.dispose();
    this.spores = [];
  }
}

// Spore: langsames Homing-Projektil, verlangsamt beim Treffen
class WispSpore {
  body: THREE.Group;
  private vel: THREE.Vector3;
  private life = SPORE_LIFE;
  dead = false;

  constructor(from: THREE.Vector3) {
    this.body = new THREE.Group();
    this.body.position.copy(from);
    this.vel = new THREE.Vector3(
      (Math.random() - 0.5) * 2,
      (Math.random() - 0.5) * 2,
      (Math.random() - 0.5) * 2
    );

    const glowMat = new THREE.MeshBasicMaterial({
      color: 0x88ffbb,
      transparent: true,
      opacity: 0.5,
      blending: THREE.AdditiveBlending,
      depthWrite: false,
    });
    const glow = new THREE.Mesh(new THREE.SphereGeometry(0.3, 10, 8), glowMat);
    this.body.add(glow);
    const coreMat = new THREE.MeshToonMaterial({ color: 0x44cc77 });
    const core = new THREE.Mesh(new THREE.SphereGeometry(0.16, 8, 6), coreMat);
    this.body.add(core);
  }

  update(dt: number, game: Game): boolean {
    this.life -= dt;

    // Sanftes Homing auf den Spieler
    if (game.player.health > 0) {
      const toPlayer = new THREE.Vector3()
        .subVectors(game.player.body.position, this.body.position)
        .normalize();
      const desired = toPlayer.multiplyScalar(SPORE_SPEED);
      this.vel.lerp(desired, Math.min(1, dt * SPORE_HOMING));
    }
    this.body.position.addScaledVector(this.vel, dt);
    this.body.position.y = Math.max(0.3, this.body.position.y);

    if (game.player.health > 0) {
      const dist = this.body.position.distanceTo(game.player.body.position);
      if (dist < SPORE_HIT_RADIUS) {
        game.player.damage(SPORE_DAMAGE, this.body.position);
        game.player.slowTimer = SPORE_SLOW;
        this.dead = true;
        return false;
      }
    }
    if (this.life <= 0) {
      this.dead = true;
      return false;
    }
    return true;
  }

  dispose() {
    this.body.removeFromParent();
    for (const child of [...this.body.children]) {
      if (child instanceof THREE.Mesh) {
        child.geometry.dispose();
        (child.material as THREE.Material).dispose();
      }
    }
  }
}
