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

const HIT_FLASH_TIME = 0.14;

// Gnom: das Ziel im Labyrinth. Stationär, nur mit Sichtlinie (durch die
// Wände hindurch) verletzbar -> man muss wirklich zu ihm hingehen.
export class Gnome extends Enemy {
  private model: THREE.Group;
  private skinMat!: THREE.MeshToonMaterial;
  private hatMat!: THREE.MeshToonMaterial;
  private beardMat!: THREE.MeshToonMaterial;
  private time = Math.random() * Math.PI * 2;
  private hitFlash = 0;

  constructor(hp: number, xp: number) {
    super();
    this.health = hp;
    this.maxHealth = hp;
    this.isBoss = true;
    this.displayName = 'Gnom';
    this.speed = 0;
    this.xp = xp;
    this.contactDps = 0;
    this.contactRadius = 0;
    this.guaranteedDrop = true;

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

    this.skinMat = new THREE.MeshToonMaterial({ color: 0xe8c8a0 });
    this.hatMat = new THREE.MeshToonMaterial({ color: 0x44aa44 });
    this.beardMat = new THREE.MeshToonMaterial({ color: 0xf8f0e0 });

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

    // Mantel
    const coat = new THREE.Mesh(new THREE.ConeGeometry(0.32, 0.45, 8, 1, true), this.hatMat);
    coat.position.y = 0.28;
    coat.rotation.x = Math.PI;
    this.registerFadeMesh(coat);
    this.model.add(coat);

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

    // Spitzer Hut
    const hat = new THREE.Mesh(new THREE.ConeGeometry(0.26, 0.55, 8), this.hatMat);
    hat.position.set(0, 1.3, 0.05);
    hat.rotation.x = 0.12;
    this.registerFadeMesh(hat);
    this.model.add(hat);

    // Bart (+Z)
    const beard = new THREE.Mesh(new THREE.SphereGeometry(0.16, 10, 8), this.beardMat);
    beard.scale.set(1, 1.2, 0.7);
    beard.position.set(0, 0.72, 0.2);
    this.registerFadeMesh(beard);
    this.model.add(beard);

    // Augen (+Z)
    const eyeMat = new THREE.MeshBasicMaterial({ color: 0x223322 });
    for (const side of [-1, 1]) {
      const eye = new THREE.Mesh(new THREE.SphereGeometry(0.04, 6, 5), eyeMat);
      eye.position.set(side * 0.09, 1.0, 0.22);
      this.model.add(eye);
    }
  }

  playAnim() {
    // Prozedurale Optik
  }

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

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

    // Hit-Feedback
    if (this.hitFlash > 0) {
      this.hitFlash -= dt;
      this.skinMat.color.set(0xffffff);
      this.hatMat.color.set(0xffffff);
    } else {
      this.skinMat.color.set(0xe8c8a0);
      this.hatMat.color.set(0x44aa44);
    }

    // Wippen + ab und zu aufhüpfen
    this.body.position.y = 0.1 + Math.abs(Math.sin(this.time * 2.2)) * 0.08;
    this.model.rotation.y = Math.sin(this.time * 1.5) * 0.15;

    // Zum Spieler drehen
    const toPlayer = new THREE.Vector3()
      .subVectors(game.player.body.position, this.body.position);
    toPlayer.y = 0;
    if (toPlayer.length() > 0.1) {
      this.body.lookAt(
        this.body.position.x + toPlayer.x,
        this.body.position.y,
        this.body.position.z + toPlayer.z
      );
    }
  }

  override takeDamage(
    damage: number,
    game: Game,
    withKnockback = true,
    sourcePos?: THREE.Vector3
  ) {
    if (this.dead) return;
    // Nur mit Sichtlinie verletzbar (kein Feuerball durch die Wand)
    const src = sourcePos ?? game.player.body.position;
    if (game.maze && !game.maze.hasLineOfSight(src, this.body.position)) {
      game.spawnDamageText('WAND!', this.body.position, '#8899aa');
      return;
    }
    super.takeDamage(damage, game, withKnockback, sourcePos);
    this.hitFlash = HIT_FLASH_TIME;
    playSound('damage', 0.6);
  }

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