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

const EXPLODE_DIST = 2.2;
const EXPLODE_RADIUS = 4.5;
const EXPLODE_DAMAGE = 30;
const FLASH_TIME = 0.35;

// Goblin-Bomber: rast auf den Spieler zu und explodiert in seiner Nähe
export class Bomber extends Enemy {
  private model: THREE.Group;
  private skinMat!: THREE.MeshToonMaterial;
  private clothMat!: THREE.MeshToonMaterial;
  private fuseMat!: THREE.MeshBasicMaterial;
  private fuse!: THREE.Mesh;
  private time = Math.random() * Math.PI * 2;
  private exploding = false;
  private flashTime = 0;
  private flashRing!: THREE.Mesh;
  private flashRingMat!: THREE.MeshBasicMaterial;

  constructor() {
    super();
    this.health = 45;
    this.speed = 6.5;
    this.xp = 18;
    this.contactDps = 0;
    this.contactRadius = 0;

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

    this.skinMat = new THREE.MeshToonMaterial({ color: 0x55aa44 });
    this.clothMat = new THREE.MeshToonMaterial({ color: 0xaa4433 });
    this.fuseMat = new THREE.MeshBasicMaterial({ color: 0xffaa33 });

    // Körper
    const body = new THREE.Mesh(new THREE.SphereGeometry(0.4, 12, 10), this.skinMat);
    body.position.y = 0.65;
    body.scale.set(1, 1.1, 1);
    body.castShadow = true;
    this.registerFadeMesh(body);
    this.model.add(body);

    // Stoff-Höschen
    const cloth = new THREE.Mesh(new THREE.ConeGeometry(0.3, 0.35, 8, 1, true), this.clothMat);
    cloth.position.y = 0.25;
    cloth.rotation.x = Math.PI;
    this.registerFadeMesh(cloth);
    this.model.add(cloth);

    // Kopf
    const head = new THREE.Mesh(new THREE.SphereGeometry(0.28, 12, 10), this.skinMat);
    head.position.y = 1.1;
    head.castShadow = true;
    this.registerFadeMesh(head);
    this.model.add(head);

    // Spitze Ohren
    for (const side of [-1, 1]) {
      const ear = new THREE.Mesh(new THREE.ConeGeometry(0.07, 0.3, 6), this.skinMat);
      ear.position.set(side * 0.22, 1.32, 0.05);
      ear.rotation.z = -side * 0.4;
      this.registerFadeMesh(ear);
      this.model.add(ear);
    }

    // Augen (+Z)
    const eyeMat = new THREE.MeshBasicMaterial({ color: 0xffdd33 });
    for (const side of [-1, 1]) {
      const eye = new THREE.Mesh(new THREE.SphereGeometry(0.06, 6, 5), eyeMat);
      eye.position.set(side * 0.1, 1.15, 0.26);
      this.model.add(eye);
    }

    // Beine
    for (const side of [-1, 1]) {
      const leg = new THREE.Mesh(new THREE.CylinderGeometry(0.07, 0.09, 0.4, 6), this.skinMat);
      leg.position.set(side * 0.15, 0.2, 0);
      this.registerFadeMesh(leg);
      this.model.add(leg);
    }

    // Zündschnur mit Glut
    const fuseGeom = new THREE.CylinderGeometry(0.03, 0.03, 0.3, 6);
    this.fuse = new THREE.Mesh(fuseGeom, this.clothMat);
    this.fuse.position.set(0, 1.45, 0);
    this.fuse.rotation.z = 0.5;
    this.registerFadeMesh(this.fuse);
    this.model.add(this.fuse);
    const spark = new THREE.Mesh(new THREE.SphereGeometry(0.07, 6, 5), this.fuseMat);
    spark.position.set(0.1, 1.6, 0);
    this.model.add(spark);

    // Explosions-Ring (Kind des Body, wird in updateAnimation animiert)
    this.flashRingMat = new THREE.MeshBasicMaterial({
      color: 0xff8833,
      transparent: true,
      opacity: 0,
      side: THREE.DoubleSide,
      depthWrite: false,
    });
    this.flashRing = new THREE.Mesh(new THREE.RingGeometry(0.9, 1.1, 32), this.flashRingMat);
    this.flashRing.rotation.x = -Math.PI / 2;
    this.flashRing.position.y = 0.07;
    this.flashRing.visible = false;
    this.body.add(this.flashRing);
  }

  playAnim() {
    // Prozedurale Optik
  }

  updateAnimation(dt: number) {
    this.updateFadeDeath(dt, { duration: 0.5, shrink: 0.8 });
    if (this.exploding && this.flashTime > 0) {
      this.flashTime -= dt;
      const t = 1 - Math.max(0, this.flashTime) / FLASH_TIME;
      this.flashRing.visible = true;
      this.flashRing.scale.setScalar(0.5 + t * 8);
      this.flashRingMat.opacity = 0.8 * (1 - t);
      if (this.flashTime <= 0) {
        this.flashRing.visible = false;
        this.flashRingMat.opacity = 0;
      }
    }
  }

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

    // Lauf-Animation: Wippen + Beine
    this.body.position.y = 0.12 + Math.abs(Math.sin(this.time * 12)) * 0.06;

    // Zündschnur glüht schneller, je näher der Gegner ist
    const distToPlayer = Math.hypot(
      game.player.body.position.x - this.body.position.x,
      game.player.body.position.z - this.body.position.z
    );
    const fusePulse = Math.min(1, 1 - distToPlayer / 12);
    this.fuseMat.color.setHSL(0.08, 1, 0.4 + fusePulse * 0.5);
    this.fuse.scale.y = 0.8 + Math.abs(Math.sin(this.time * (4 + fusePulse * 16))) * 0.5;

    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
      );
      let moveDir = dir.multiplyScalar(this.speed);
      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);
    }

    // Explosion bei Annäherung
    if (dist <= EXPLODE_DIST && game.player.health > 0 && !this.dead) {
      this.explode(game);
    }
  }

  private explode(game: Game) {
    this.exploding = true;
    this.flashTime = FLASH_TIME;
    this.flashRing.scale.setScalar(0.5);
    this.flashRing.visible = true;
    this.flashRing.position.set(this.body.position.x, 0.07, this.body.position.z);
    this.fuseMat.color.set(0xffffff);
    playSound('explosion', 0.8);
    game.triggerCameraShake(0.3, 0.35);

    if (game.player.health > 0) {
      const dx = game.player.body.position.x - this.body.position.x;
      const dz = game.player.body.position.z - this.body.position.z;
      if (Math.hypot(dx, dz) < EXPLODE_RADIUS && game.player.body.position.y <= 0.8) {
        game.player.damage(EXPLODE_DAMAGE, this.body.position);
      }
    }
    this.takeDamage(99999, game, false);
  }

  protected onDeath(_game: Game) {
    if (!this.exploding) {
      playSound('damage', 0.5);
    }
    this.beginFadeDeath();
  }

  override dispose() {
    super.dispose();
    this.flashRing.geometry.dispose();
    this.flashRingMat.dispose();
  }
}
