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

const STRAFE_DIST = 3.2;
const SHELL_IN = 0.4;
const SHELL_TIME = 2.0;
const SHELL_OUT = 0.4;
const SHELL_CYCLE = 7;
const HIT_FLASH_TIME = 0.14;

type State = 'strafe' | 'shellin' | 'shell' | 'shellout';

// Schildkröte: Frontpanzerung blockt Schaden komplett, zieht sich periodisch in den Panzer zurück
export class Turtle extends Enemy {
  private model: THREE.Group;
  private shellMat!: THREE.MeshToonMaterial;
  private darkMat!: THREE.MeshToonMaterial;
  private skinMat!: THREE.MeshToonMaterial;
  private shell!: THREE.Mesh;
  private headMesh!: THREE.Mesh;
  private legs: THREE.Mesh[] = [];
  private eyeMat!: THREE.MeshBasicMaterial;
  private state: State = 'strafe';
  private stateTimer = 0;
  private shellTimer = SHELL_CYCLE * 0.6;
  private side = Math.random() < 0.5 ? 1 : -1;
  private time = Math.random() * Math.PI * 2;
  private hitFlash = 0;

  constructor() {
    super();
    this.health = 160;
    this.speed = 2.8;
    this.xp = 30;
    this.contactDps = 18;
    this.contactRadius = 1.8;

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

    this.shellMat = new THREE.MeshToonMaterial({ color: 0x55aa55 });
    this.darkMat = new THREE.MeshToonMaterial({ color: 0x2f5c2f });
    this.skinMat = new THREE.MeshToonMaterial({ color: 0x99bb77 });
    this.eyeMat = new THREE.MeshBasicMaterial({ color: 0x223322 });

    // Panzer (Kuppel)
    this.shell = new THREE.Mesh(new THREE.SphereGeometry(0.85, 18, 12, 0, Math.PI * 2, 0, Math.PI / 2), this.shellMat);
    this.shell.position.y = 0.6;
    this.shell.castShadow = true;
    this.registerFadeMesh(this.shell);
    this.model.add(this.shell);

    // Panzer-Platten
    for (let i = 0; i < 4; i++) {
      const plate = new THREE.Mesh(
        new THREE.BoxGeometry(0.5, 0.08, 0.3),
        this.darkMat
      );
      const a = (i / 4) * Math.PI * 2;
      plate.position.set(Math.cos(a) * 0.55, 0.85, Math.sin(a) * 0.55);
      plate.rotation.y = -a;
      plate.scale.set(1.3, 1, 1);
      this.registerFadeMesh(plate);
      this.model.add(plate);
    }

    // Beine
    for (const side of [-1, 1]) {
      for (const back of [true, false]) {
        const leg = new THREE.Mesh(new THREE.CylinderGeometry(0.12, 0.15, 0.25, 6), this.skinMat);
        leg.position.set(side * 0.55, 0.15, back ? -0.45 : 0.5);
        this.registerFadeMesh(leg);
        this.model.add(leg);
        this.legs.push(leg);
      }
    }

    // Kopf (+Z)
    this.headMesh = new THREE.Mesh(new THREE.SphereGeometry(0.22, 10, 8), this.skinMat);
    this.headMesh.scale.set(1, 0.8, 1.3);
    this.headMesh.position.set(0, 0.35, 0.9);
    this.registerFadeMesh(this.headMesh);
    this.model.add(this.headMesh);

    // Augen (+Z)
    for (const side of [-1, 1]) {
      const eye = new THREE.Mesh(new THREE.SphereGeometry(0.05, 6, 5), this.eyeMat);
      eye.position.set(side * 0.12, 0.45, 1.05);
      this.model.add(eye);
    }

    // Schwanzstummel (-Z)
    const tail = new THREE.Mesh(new THREE.ConeGeometry(0.1, 0.3, 6), this.skinMat);
    tail.rotation.x = Math.PI / 2;
    tail.position.set(0, 0.2, -0.95);
    this.registerFadeMesh(tail);
    this.model.add(tail);
  }

  playAnim() {
    // Prozedurale Optik
  }

  updateAnimation(dt: number) {
    this.updateFadeDeath(dt, { duration: 1.0, sink: 0.4 });
  }

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

    // Hit-Feedback
    if (this.hitFlash > 0) {
      this.hitFlash -= dt;
      this.shellMat.color.set(0xffffff);
      this.skinMat.color.set(0xffffff);
    } else {
      this.shellMat.color.set(0x55aa55);
      this.skinMat.color.set(0x99bb77);
    }

    const toPlayer = new THREE.Vector3()
      .subVectors(game.player.body.position, this.body.position);
    toPlayer.y = 0;
    const dist = toPlayer.length();

    switch (this.state) {
      case 'strafe':
        this.stateTimer -= dt;
        this.shellTimer -= dt;
        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
          );
          if (this.knockback > 0) {
            this.knockback -= dt;
            const away = dir.clone().multiplyScalar(-this.speed);
            this.body.position.x += away.x * dt;
            this.body.position.z += away.z * dt;
          } else {
            // Seitwärts kreisen (Panzerfront zeigt zum Spieler)
            if (Math.random() < dt * 0.25) this.side *= -1;
            const perp = new THREE.Vector3(-dir.z, 0, dir.x);
            const move = perp.multiplyScalar(this.side * this.speed);
            this.body.position.x += move.x * dt;
            this.body.position.z += move.z * dt;
          }
          game.clampToArena(this.body.position);
        }
        if (this.shellTimer <= 0) {
          this.shellTimer = SHELL_CYCLE;
          this.state = 'shellin';
          this.stateTimer = SHELL_IN;
          playSound('spawn', 0.4);
        }
        break;

      case 'shellin':
        this.stateTimer -= dt;
        this.shell.scale.y = THREE.MathUtils.lerp(this.shell.scale.y, 1.25, 0.25);
        this.headMesh.visible = this.shell.scale.y < 1.1;
        if (this.stateTimer <= 0) {
          this.state = 'shell';
          this.stateTimer = SHELL_TIME;
          this.shell.scale.y = 1.25;
          this.headMesh.visible = false;
          for (const leg of this.legs) leg.visible = false;
        }
        break;

      case 'shell':
        this.stateTimer -= dt;
        if (this.stateTimer <= 0) {
          this.state = 'shellout';
          this.stateTimer = SHELL_OUT;
          this.headMesh.visible = true;
          for (const leg of this.legs) leg.visible = true;
        }
        break;

      case 'shellout':
        this.stateTimer -= dt;
        this.shell.scale.y = THREE.MathUtils.lerp(this.shell.scale.y, 1, 0.25);
        if (this.stateTimer <= 0) {
          this.state = 'strafe';
          this.shell.scale.y = 1;
        }
        break;
    }
  }

  override takeDamage(
    damage: number,
    game: Game,
    withKnockback = true,
    sourcePos?: THREE.Vector3
  ) {
    if (this.dead) return;
    // Im Panzer komplett unverwundbar
    if (this.state === 'shell' || this.state === 'shellin') return;

    const src = sourcePos ?? game.player.body.position;
    const front = new THREE.Vector3(0, 0, 1).applyQuaternion(this.body.quaternion);
    front.y = 0;
    front.normalize();
    const incoming = new THREE.Vector3().subVectors(src, this.body.position);
    incoming.y = 0;
    if (incoming.lengthSq() < 0.0001) incoming.copy(front);
    incoming.normalize();

    // Frontpanzerung blockt kompletten Schaden
    if (front.dot(incoming) > 0.3) {
      game.spawnDamageText('PANZER!', this.body.position, '#88cc66');
      playSound('sword_hit1', 0.5);
      return;
    }

    super.takeDamage(damage, game, withKnockback, sourcePos);
    this.hitFlash = HIT_FLASH_TIME;
  }

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