import { type GameEffect } from '../core/gameResult'
import { type AnimationLevel } from '../../utils/animationLevel'
import {
  DEFAULT_GAME_UI_EFFECTS_CONFIG,
  type FeedbackCueKey,
  type GameUiEffectsConfig,
  type UiContentCardMotion,
  type UiHudDistanceMotion,
  type UiHudProgressMotion,
  type UiMapPulseMotion,
  type UiPunchButtonMotion,
  type UiPunchFeedbackMotion,
  type UiCueConfig,
  type UiStageMotion,
} from './feedbackConfig'

export interface UiEffectHost {
  showPunchFeedback: (text: string, tone: 'neutral' | 'success' | 'warning', motionClass?: string) => void
  showContentCard: (title: string, body: string, motionClass?: string, options?: { contentKey?: string; autoPopup?: boolean; once?: boolean; priority?: number }) => void
  setPunchButtonFxClass: (className: string) => void
  setHudProgressFxClass: (className: string) => void
  setHudDistanceFxClass: (className: string) => void
  showMapPulse: (controlId: string, motionClass?: string) => void
  showStageFx: (className: string) => void
}

export class UiEffectDirector {
  enabled: boolean
  config: GameUiEffectsConfig
  host: UiEffectHost
  punchButtonMotionTimer: number
  hudProgressMotionTimer: number
  hudDistanceMotionTimer: number
  punchButtonMotionToggle: boolean
  animationLevel: AnimationLevel

  constructor(host: UiEffectHost, config: GameUiEffectsConfig = DEFAULT_GAME_UI_EFFECTS_CONFIG) {
    this.enabled = true
    this.host = host
    this.config = config
    this.punchButtonMotionTimer = 0
    this.hudProgressMotionTimer = 0
    this.hudDistanceMotionTimer = 0
    this.punchButtonMotionToggle = false
    this.animationLevel = 'standard'
  }

  configure(config: GameUiEffectsConfig): void {
    this.config = config
    this.clearPunchButtonMotion()
    this.clearHudProgressMotion()
    this.clearHudDistanceMotion()
  }

  setEnabled(enabled: boolean): void {
    this.enabled = enabled
    if (!enabled) {
      this.clearPunchButtonMotion()
      this.clearHudProgressMotion()
      this.clearHudDistanceMotion()
    }
  }

  setAnimationLevel(level: AnimationLevel): void {
    this.animationLevel = level
  }

  destroy(): void {
    this.clearPunchButtonMotion()
    this.clearHudProgressMotion()
    this.clearHudDistanceMotion()
  }

  clearPunchButtonMotion(): void {
    if (this.punchButtonMotionTimer) {
      clearTimeout(this.punchButtonMotionTimer)
      this.punchButtonMotionTimer = 0
    }
    this.host.setPunchButtonFxClass('')
  }

  clearHudProgressMotion(): void {
    if (this.hudProgressMotionTimer) {
      clearTimeout(this.hudProgressMotionTimer)
      this.hudProgressMotionTimer = 0
    }
    this.host.setHudProgressFxClass('')
  }

  clearHudDistanceMotion(): void {
    if (this.hudDistanceMotionTimer) {
      clearTimeout(this.hudDistanceMotionTimer)
      this.hudDistanceMotionTimer = 0
    }
    this.host.setHudDistanceFxClass('')
  }

  getPunchFeedbackMotionClass(motion: UiPunchFeedbackMotion): string {
    if (motion === 'warning') {
      return 'game-punch-feedback--fx-warning'
    }
    if (motion === 'success') {
      return 'game-punch-feedback--fx-success'
    }
    if (motion === 'pop') {
      return 'game-punch-feedback--fx-pop'
    }
    return ''
  }

  getContentCardMotionClass(motion: UiContentCardMotion): string {
    if (motion === 'finish') {
      return 'game-content-card--fx-finish'
    }
    if (motion === 'pop') {
      return 'game-content-card--fx-pop'
    }
    return ''
  }

  getMapPulseMotionClass(motion: UiMapPulseMotion): string {
    if (motion === 'ready') {
      return 'map-stage__map-pulse--ready'
    }
    if (motion === 'finish') {
      return 'map-stage__map-pulse--finish'
    }
    if (motion === 'control') {
      return 'map-stage__map-pulse--control'
    }
    return ''
  }

  getStageMotionClass(motion: UiStageMotion): string {
    if (motion === 'control') {
      return 'map-stage__stage-fx--control'
    }
    if (motion === 'finish') {
      return 'map-stage__stage-fx--finish'
    }
    return ''
  }

  getHudProgressMotionClass(motion: UiHudProgressMotion): string {
    if (motion === 'finish') {
      return 'race-panel__progress--fx-finish'
    }
    if (motion === 'success') {
      return 'race-panel__progress--fx-success'
    }
    return ''
  }

  getHudDistanceMotionClass(motion: UiHudDistanceMotion): string {
    if (motion === 'success') {
      return 'race-panel__metric-group--fx-distance-success'
    }
    return ''
  }

  triggerPunchButtonMotion(motion: UiPunchButtonMotion, durationMs: number): void {
    if (motion === 'none') {
      return
    }

    this.punchButtonMotionToggle = !this.punchButtonMotionToggle
    const variant = this.punchButtonMotionToggle ? 'a' : 'b'
    const className = motion === 'warning'
      ? `map-punch-button--fx-warning-${variant}`
      : `map-punch-button--fx-ready-${variant}`

    this.host.setPunchButtonFxClass(className)
    if (this.punchButtonMotionTimer) {
      clearTimeout(this.punchButtonMotionTimer)
    }
    this.punchButtonMotionTimer = setTimeout(() => {
      this.punchButtonMotionTimer = 0
      this.host.setPunchButtonFxClass('')
    }, durationMs) as unknown as number
  }

  triggerHudProgressMotion(motion: UiHudProgressMotion, durationMs: number): void {
    const className = this.getHudProgressMotionClass(motion)
    if (!className) {
      return
    }
    this.host.setHudProgressFxClass(className)
    if (this.hudProgressMotionTimer) {
      clearTimeout(this.hudProgressMotionTimer)
    }
    this.hudProgressMotionTimer = setTimeout(() => {
      this.hudProgressMotionTimer = 0
      this.host.setHudProgressFxClass('')
    }, durationMs) as unknown as number
  }

  triggerHudDistanceMotion(motion: UiHudDistanceMotion, durationMs: number): void {
    const className = this.getHudDistanceMotionClass(motion)
    if (!className) {
      return
    }
    this.host.setHudDistanceFxClass(className)
    if (this.hudDistanceMotionTimer) {
      clearTimeout(this.hudDistanceMotionTimer)
    }
    this.hudDistanceMotionTimer = setTimeout(() => {
      this.hudDistanceMotionTimer = 0
      this.host.setHudDistanceFxClass('')
    }, durationMs) as unknown as number
  }

  getCue(key: FeedbackCueKey): UiCueConfig | null {
    if (!this.enabled || !this.config.enabled) {
      return null
    }

    const cue = this.config.cues[key]
    if (!cue || !cue.enabled) {
      return null
    }

    if (this.animationLevel === 'standard') {
      return cue
    }

    return {
      ...cue,
      stageMotion: 'none' as const,
      hudDistanceMotion: 'none' as const,
      durationMs: cue.durationMs > 0 ? Math.max(260, Math.round(cue.durationMs * 0.6)) : 0,
    }
  }

  handleEffects(effects: GameEffect[]): void {
    for (const effect of effects) {
      if (effect.type === 'punch_feedback' && effect.tone === 'warning') {
        const cue = this.getCue('punch_feedback:warning')
        this.host.showPunchFeedback(
          effect.text,
          effect.tone,
          cue ? this.getPunchFeedbackMotionClass(cue.punchFeedbackMotion) : '',
        )
        if (cue) {
          this.triggerPunchButtonMotion(cue.punchButtonMotion, cue.durationMs)
        }
        continue
      }

      if (effect.type === 'control_completed') {
        const key: FeedbackCueKey = effect.controlKind === 'start'
          ? 'control_completed:start'
          : effect.controlKind === 'finish'
            ? 'control_completed:finish'
            : 'control_completed:control'
        const cue = this.getCue(key)
        this.host.showPunchFeedback(
          `完成 ${typeof effect.sequence === 'number' ? effect.sequence : effect.label}`,
          'success',
          cue ? this.getPunchFeedbackMotionClass(cue.punchFeedbackMotion) : '',
        )
        if (effect.controlKind !== 'finish' && effect.displayAutoPopup) {
          this.host.showContentCard(
            effect.displayTitle,
            effect.displayBody,
            cue ? this.getContentCardMotionClass(cue.contentCardMotion) : '',
            {
              contentKey: effect.controlId,
              autoPopup: effect.displayAutoPopup,
              once: effect.displayOnce,
              priority: effect.displayPriority,
            },
          )
        }
        if (cue && cue.mapPulseMotion !== 'none') {
          this.host.showMapPulse(effect.controlId, this.getMapPulseMotionClass(cue.mapPulseMotion))
        }
        if (cue && cue.stageMotion !== 'none') {
          this.host.showStageFx(this.getStageMotionClass(cue.stageMotion))
        }
        if (cue) {
          this.triggerHudProgressMotion(cue.hudProgressMotion, cue.durationMs)
          this.triggerHudDistanceMotion(cue.hudDistanceMotion, cue.durationMs)
        }
        continue
      }

      if (effect.type === 'guidance_state_changed' && effect.guidanceState === 'ready') {
        const cue = this.getCue('guidance:ready')
        if (cue) {
          this.triggerPunchButtonMotion(cue.punchButtonMotion, cue.durationMs)
          if (cue.mapPulseMotion !== 'none' && effect.controlId) {
            this.host.showMapPulse(effect.controlId, this.getMapPulseMotionClass(cue.mapPulseMotion))
          }
        }
        continue
      }

      if (effect.type === 'session_finished') {
        this.clearPunchButtonMotion()
        this.clearHudProgressMotion()
        this.clearHudDistanceMotion()
      }

      if (effect.type === 'session_cancelled') {
        this.clearPunchButtonMotion()
        this.clearHudProgressMotion()
        this.clearHudDistanceMotion()
      }
    }
  }
}
