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

const HEAL_RADIUS = 8;
const HEAL_TICK = 0.9;
const HEAL_AMOUNT = 6;
const HIT_FLASH_TIME = 0.14;

// Schamane: heilt andere Gegner im Radius -> Prioritätsziel
export class Shaman extends Enemy {
  private model: THREE.Group;
  private robeMat!: THREE.MeshToonMaterial;
  private darkMat!: THREE.MeshToonMaterial;
  private healRing!: THREE.Mesh;
  private healRingMat!: THREE.MeshBasicMaterial;
  private healTimer = 0.5;
  private time = Math.random() * Math.PI * 2;
  private hitFlash = 0;

  constructor() {
    super();
    this.health = 60;
    this.speed = 2.8;
    this.xp = 25;
    this.contactDps = 10;
    this.contactRadius = 1.8;

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

    this.robeMat = new THREE.MeshToonMaterial({ color: 0x33aa55, emissive: 0x0a1f10 });
    this.darkMat = new THREE.MeshToonMaterial({ color: 0x1c5c2e });
    const boneMat = new THREE.MeshToonMaterial({ color: 0xe8dcc0 });
    const faceMat = new THREE.MeshBasicMaterial({ color: 0x06120a });
    let boneFadeRegistered = false;
    const registerBone = (mesh: THREE.Mesh) => {
      // Knochen-Material einmal fürs Fade-Death registrieren (wird geteilt)
      if (!boneFadeRegistered) {
        this.registerFadeMesh(mesh);
        boneFadeRegistered = true;
      }
    };

    // --- Robe (Blickrichtung +Z, bis zum Boden) ---
    const robeProfile = [
      new THREE.Vector2(0.52, 0.02), // Saum
      new THREE.Vector2(0.44, 0.35),
      new THREE.Vector2(0.32, 0.7),
      new THREE.Vector2(0.3, 0.95),
      new THREE.Vector2(0.38, 1.1), // Schulteransatz
      new THREE.Vector2(0.24, 1.25), // Hals
    ];
    const robe = new THREE.Mesh(new THREE.LatheGeometry(robeProfile, 12), this.robeMat);
    robe.castShadow = true;
    this.registerFadeMesh(robe);
    this.model.add(robe);

    // Zerfetzter Saum
    for (let i = 0; i < 6; i++) {
      const a = (i / 6) * Math.PI * 2;
      const tatter = new THREE.Mesh(
        new THREE.ConeGeometry(0.06, 0.28, 4),
        i % 2 === 0 ? this.robeMat : this.darkMat
      );
      tatter.rotation.x = Math.PI;
      tatter.position.set(Math.sin(a) * 0.48, -0.02, Math.cos(a) * 0.48);
      this.registerFadeMesh(tatter);
      this.model.add(tatter);
    }

    // Gürtel mit hängenden Knochen-Amuletten
    const belt = new THREE.Mesh(new THREE.TorusGeometry(0.33, 0.03, 6, 14), this.darkMat);
    belt.rotation.x = Math.PI / 2;
    belt.position.y = 0.75;
    this.registerFadeMesh(belt);
    this.model.add(belt);
    for (const [x, z] of [[-0.14, 0.3], [0, 0.34], [0.14, 0.3]] as const) {
      const charm = new THREE.Mesh(new THREE.CylinderGeometry(0.02, 0.02, 0.16, 5), boneMat);
      charm.position.set(x, 0.62, z);
      registerBone(charm);
      this.model.add(charm);
    }

    // Brust + Fellkragen mit Zacken
    const chest = new THREE.Mesh(new THREE.SphereGeometry(0.28, 12, 10), this.robeMat);
    chest.position.y = 1.12;
    chest.scale.set(1, 1.15, 1);
    this.registerFadeMesh(chest);
    this.model.add(chest);
    const collar = new THREE.Mesh(new THREE.TorusGeometry(0.26, 0.09, 8, 14), this.darkMat);
    collar.rotation.x = Math.PI / 2;
    collar.scale.set(1, 1, 0.8);
    collar.position.y = 1.28;
    this.registerFadeMesh(collar);
    this.model.add(collar);
    for (let i = 0; i < 8; i++) {
      const a = (i / 8) * Math.PI * 2;
      const fur = new THREE.Mesh(new THREE.ConeGeometry(0.04, 0.16, 4), this.darkMat);
      fur.position.set(Math.sin(a) * 0.28, 1.36, Math.cos(a) * 0.24);
      fur.rotation.x = -0.4;
      fur.rotation.y = a;
      this.registerFadeMesh(fur);
      this.model.add(fur);
    }

    // Knochenkette mit Zähnen auf der Brust
    const necklace = new THREE.Mesh(new THREE.TorusGeometry(0.16, 0.02, 6, 12), this.darkMat);
    necklace.rotation.x = Math.PI / 2 - 0.3;
    necklace.position.set(0, 1.2, 0.2);
    this.registerFadeMesh(necklace);
    this.model.add(necklace);
    for (const [x, z] of [[-0.08, 0.32], [0, 0.35], [0.08, 0.32]] as const) {
      const tooth = new THREE.Mesh(new THREE.ConeGeometry(0.03, 0.1, 4), boneMat);
      tooth.rotation.x = Math.PI;
      tooth.position.set(x, 1.1, z);
      registerBone(tooth);
      this.model.add(tooth);
    }

    // Kapuze mit Krempe, schwarzem Gesicht und grünen Augen (+Z)
    const hood = new THREE.Mesh(new THREE.ConeGeometry(0.32, 0.6, 10, 1, true), this.darkMat);
    hood.position.set(0, 1.55, 0.02);
    hood.rotation.x = 0.2;
    hood.castShadow = true;
    this.registerFadeMesh(hood);
    this.model.add(hood);
    const hoodRim = new THREE.Mesh(new THREE.TorusGeometry(0.22, 0.04, 8, 14), this.darkMat);
    hoodRim.rotation.x = -0.5;
    hoodRim.position.set(0, 1.44, 0.22);
    this.registerFadeMesh(hoodRim);
    this.model.add(hoodRim);
    const face = new THREE.Mesh(new THREE.SphereGeometry(0.2, 12, 10), faceMat);
    face.scale.set(1, 1.1, 0.8);
    face.position.set(0, 1.44, 0.16);
    this.registerFadeMesh(face);
    this.model.add(face);
    const eyeMat = new THREE.MeshBasicMaterial({ color: 0x66ff88 });
    for (const side of [-1, 1]) {
      const eye = new THREE.Mesh(new THREE.SphereGeometry(0.055, 6, 5), eyeMat);
      eye.position.set(side * 0.08, 1.47, 0.35);
      this.model.add(eye);
    }

    // Federn an der Kapuze (hängen nach hinten)
    for (const side of [-1, 1]) {
      const feather = new THREE.Mesh(new THREE.ConeGeometry(0.05, 0.4, 4), boneMat);
      feather.rotation.x = Math.PI + side * 0.15;
      feather.scale.set(1, 1, 0.3);
      feather.position.set(side * 0.14, 1.35, -0.22);
      registerBone(feather);
      this.model.add(feather);
    }

    // Rechter Arm zum Stab
    const sleeveR = new THREE.Mesh(new THREE.CylinderGeometry(0.07, 0.12, 0.45, 8), this.robeMat);
    sleeveR.position.set(0.32, 1.05, 0.1);
    sleeveR.rotation.z = 1.0;
    this.registerFadeMesh(sleeveR);
    this.model.add(sleeveR);
    const handR = new THREE.Mesh(new THREE.SphereGeometry(0.07, 8, 6), boneMat);
    handR.position.set(0.45, 0.95, 0.18);
    registerBone(handR);
    this.model.add(handR);

    // Linker Arm erhoben mit kleiner Energiekugel
    const sleeveL = new THREE.Mesh(new THREE.CylinderGeometry(0.07, 0.12, 0.45, 8), this.robeMat);
    sleeveL.position.set(-0.34, 1.12, 0.18);
    sleeveL.rotation.x = -1.1;
    sleeveL.rotation.z = -0.5;
    this.registerFadeMesh(sleeveL);
    this.model.add(sleeveL);
    const handL = new THREE.Mesh(new THREE.SphereGeometry(0.07, 8, 6), boneMat);
    handL.position.set(-0.4, 1.22, 0.34);
    registerBone(handL);
    this.model.add(handL);

    const orbMat = new THREE.MeshBasicMaterial({
      color: 0x66ff88,
      transparent: true,
      opacity: 0.9,
      blending: THREE.AdditiveBlending,
      depthWrite: false,
    });
    const castOrb = new THREE.Mesh(new THREE.SphereGeometry(0.07, 8, 6), orbMat);
    castOrb.position.set(-0.42, 1.38, 0.38);
    this.model.add(castOrb);

    // Totem-Stab: Schädel mit Klauenkrone, Glüh-Orb, hängender Anhänger
    const staff = new THREE.Mesh(new THREE.CylinderGeometry(0.03, 0.04, 1.7, 6), this.darkMat);
    staff.position.set(0.5, 0.85, 0.2);
    staff.rotation.z = 0.15;
    staff.rotation.x = 0.1;
    this.registerFadeMesh(staff);
    this.model.add(staff);
    const skull = new THREE.Mesh(new THREE.SphereGeometry(0.11, 10, 8), boneMat);
    skull.position.set(0.37, 1.72, 0.29);
    registerBone(skull);
    this.model.add(skull);
    for (const side of [-1, 1]) {
      const claw = new THREE.Mesh(new THREE.ConeGeometry(0.03, 0.22, 5), boneMat);
      claw.position.set(0.37 + side * 0.1, 1.84, 0.29);
      claw.rotation.z = side * -0.5;
      registerBone(claw);
      this.model.add(claw);
      const socket = new THREE.Mesh(new THREE.SphereGeometry(0.025, 6, 4), this.darkMat);
      socket.position.set(0.37 + side * 0.04, 1.74, 0.39);
      this.model.add(socket);
    }
    const orb = new THREE.Mesh(new THREE.SphereGeometry(0.09, 8, 6), orbMat);
    orb.position.set(0.37, 1.94, 0.29);
    this.model.add(orb);
    const dangle = new THREE.Mesh(new THREE.CylinderGeometry(0.015, 0.015, 0.14, 5), boneMat);
    dangle.position.set(0.44, 1.58, 0.27);
    dangle.rotation.z = 0.4;
    registerBone(dangle);
    this.model.add(dangle);

    // Heil-Aura-Ring am Boden
    this.healRingMat = new THREE.MeshBasicMaterial({
      color: 0x44ff77,
      transparent: true,
      opacity: 0,
      side: THREE.DoubleSide,
      depthWrite: false,
    });
    this.healRing = new THREE.Mesh(
      new THREE.RingGeometry(HEAL_RADIUS - 0.15, HEAL_RADIUS + 0.15, 32),
      this.healRingMat
    );
    this.healRing.rotation.x = -Math.PI / 2;
    this.healRing.position.y = 0.05;
    this.body.add(this.healRing);
  }

  playAnim() {
    // Prozedurale Optik
  }

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

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

    // Hit-Feedback
    if (this.hitFlash > 0) {
      this.hitFlash -= dt;
      this.robeMat.color.set(0xffffff);
      this.darkMat.color.set(0xffffff);
    } else {
      this.robeMat.color.set(0x33aa55);
      this.darkMat.color.set(0x1c5c2e);
    }

    // Langsames Schwebe-Wippen
    this.model.rotation.z = Math.sin(this.time * 1.5) * 0.04;

    // Zum Spieler laufen
    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);
    }

    // Heil-Tick
    this.healTimer -= dt;
    if (this.healTimer <= 0) {
      this.healTimer = HEAL_TICK;
      let healed = false;
      for (const e of game.enemies) {
        if (e === this || e.dead) continue;
        const d = Math.hypot(
          e.body.position.x - this.body.position.x,
          e.body.position.z - this.body.position.z
        );
        if (d < HEAL_RADIUS && e.health < e.maxHealth) {
          e.health = Math.min(e.maxHealth, e.health + HEAL_AMOUNT);
          healed = true;
        }
      }
      if (healed) playSound('spawn', 0.35);
    }

    // Aura-Ring pulsiert mit dem Tick
    const pulse = 0.15 + Math.max(0, this.healTimer / HEAL_TICK) * 0.25;
    this.healRingMat.opacity = pulse;
  }

  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.beginFadeDeath();
  }

  override dispose() {
    super.dispose();
    this.healRing.geometry.dispose();
    this.healRingMat.dispose();
  }
}
