import 'package:flutter/foundation.dart';

import 'package:asciineverdie/data/story_data.dart';
import 'package:asciineverdie/src/core/audio/audio_service.dart';
import 'package:asciineverdie/src/core/model/combat_event.dart';
import 'package:asciineverdie/src/core/model/game_state.dart';
import 'package:asciineverdie/src/core/model/monster_grade.dart';

/// 게임 오디오 컨트롤러
///
/// GamePlayScreen에서 추출된 오디오 관련 로직 담당:
/// - BGM 전환 (전투/마을/사망/엔딩)
/// - 전투 이벤트 SFX 재생
/// - 볼륨 관리
class GameAudioController extends ChangeNotifier {
  GameAudioController({required this.audioService, this.getSpeedMultiplier});

  final AudioService? audioService;

  /// 현재 배속 값을 가져오는 콜백 (디바운스 계산용)
  final int Function()? getSpeedMultiplier;

  // 오디오 상태 추적
  bool _wasInBattleTask = false;
  bool _wasDead = false;
  bool _wasComplete = false;

  // 볼륨 상태
  double _bgmVolume = 0.7;
  double _sfxVolume = 0.8;

  // SFX 디바운스 추적
  final Map<String, int> _lastSfxPlayTime = {};

  // Getters
  double get bgmVolume => _bgmVolume;
  double get sfxVolume => _sfxVolume;

  /// 오디오 볼륨 초기화 (AudioService에서 로드)
  Future<void> initVolumes() async {
    final audio = audioService;
    if (audio != null) {
      _bgmVolume = audio.bgmVolume;
      _sfxVolume = audio.sfxVolume;
      notifyListeners();
    }
  }

  /// BGM 볼륨 설정
  void setBgmVolume(double volume) {
    _bgmVolume = volume;
    audioService?.setBgmVolume(volume);
    notifyListeners();
  }

  /// SFX 볼륨 설정
  void setSfxVolume(double volume) {
    _sfxVolume = volume;
    audioService?.setSfxVolume(volume);
    notifyListeners();
  }

  /// 일시정지
  void pauseAll() {
    audioService?.pauseAll();
  }

  /// 재개
  void resumeAll() {
    audioService?.resumeAll();
  }

  /// 초기 BGM 재생 (게임 시작/로드 시)
  void playInitialBgm(GameState state) {
    final audio = audioService;
    if (audio == null) return;

    final taskType = state.progress.currentTask.type;
    final isInBattleTask = taskType == TaskType.kill;

    if (isInBattleTask) {
      audio.playBgm(_getBattleBgm(state));
    } else {
      // 비전투 태스크: 마을 BGM
      audio.playBgm('town');
    }

    _wasInBattleTask = isInBattleTask;
  }

  /// TaskType 기반 BGM 전환 (애니메이션과 동기화)
  void updateBgmForTaskType(GameState state) {
    final audio = audioService;
    if (audio == null) return;

    final taskType = state.progress.currentTask.type;
    final isInBattleTask = taskType == TaskType.kill;

    if (isInBattleTask) {
      final expectedBgm = _getBattleBgm(state);

      // 전환 시점이거나 현재 BGM이 일치하지 않으면 재생
      if (!_wasInBattleTask || audio.currentBgm != expectedBgm) {
        audio.playBgm(expectedBgm);
      }
    } else {
      // 비전투 태스크: 항상 마을 BGM 유지 (이미 town이면 스킵)
      if (audio.currentBgm != 'town') {
        audio.playBgm('town');
      }
    }

    _wasInBattleTask = isInBattleTask;
  }

  /// 사망/엔딩 BGM 전환 처리
  void updateDeathEndingBgm(GameState state, {required bool isGameComplete}) {
    final audio = audioService;
    if (audio == null) return;

    final isDead = state.isDead;

    // 엔딩 BGM (게임 클리어 시)
    if (isGameComplete && !_wasComplete) {
      audio.playBgm('ending');
      _wasComplete = true;
      return;
    }

    // 사망 BGM (isDead 상태 진입 시)
    if (isDead && !_wasDead) {
      audio.playBgm('death');
      _wasDead = true;
      return;
    }

    // 부활 시 사망 상태 리셋 (다음 사망 감지 가능하도록)
    if (!isDead && _wasDead) {
      _wasDead = false;
      // 부활 후 BGM은 updateBgmForTaskType에서 처리됨
    }
  }

  /// 시네마틱 BGM 재생
  void playCinematicBgm() {
    audioService?.playBgm('act_cinemetic');
  }

  /// 레벨업 SFX 재생
  void playLevelUpSfx() {
    audioService?.playPlayerSfx('level_up');
  }

  /// 퀘스트 완료 SFX 재생
  void playQuestCompleteSfx() {
    audioService?.playPlayerSfx('quest_complete');
  }

  /// 전투 이벤트별 SFX 재생 (채널 분리 + 디바운스)
  void playCombatEventSfx(CombatEvent event) {
    final audio = audioService;
    if (audio == null) return;

    // 사운드 이름 결정
    final sfxName = switch (event.type) {
      CombatEventType.playerAttack => 'attack',
      CombatEventType.playerSkill => 'skill',
      CombatEventType.playerHeal => 'item',
      CombatEventType.playerPotion => 'item',
      CombatEventType.potionDrop => 'item',
      CombatEventType.playerBuff => 'skill',
      CombatEventType.playerDebuff => 'skill',
      CombatEventType.monsterAttack => 'hit',
      CombatEventType.playerEvade => 'evade',
      CombatEventType.monsterEvade => 'evade',
      CombatEventType.playerBlock => 'block',
      CombatEventType.playerParry => 'parry',
      CombatEventType.dotTick => null, // DOT 틱은 SFX 없음
    };

    if (sfxName == null) return;

    // 디바운스 체크 (배속 시 같은 사운드 중복 재생 방지)
    final now = DateTime.now().millisecondsSinceEpoch;
    final lastTime = _lastSfxPlayTime[sfxName] ?? 0;
    final speedMultiplier = getSpeedMultiplier?.call() ?? 1;

    // 배속이 높을수록 디바운스 간격 증가 (1x=50ms, 8x=150ms)
    final debounceMs = 50 + (speedMultiplier - 1) * 15;

    if (now - lastTime < debounceMs) {
      return; // 디바운스 기간 내 → 스킵
    }
    _lastSfxPlayTime[sfxName] = now;

    // 채널별 재생
    final isMonsterSfx = event.type == CombatEventType.monsterAttack;
    if (isMonsterSfx) {
      audio.playMonsterSfx(sfxName);
    } else {
      audio.playPlayerSfx(sfxName);
    }
  }

  /// 전투 BGM 결정 (몬스터 등급 + 레벨 + Act 고려)
  String _getBattleBgm(GameState state) {
    final task = state.progress.currentTask;
    final monsterGrade = task.monsterGrade;
    final monsterLevel = task.monsterLevel ?? 0;
    final playerLevel = state.traits.level;

    // 1. 등급 보스 (3% 확률로 등장하는 특수 보스)
    if (monsterGrade == MonsterGrade.boss) {
      return 'act_boss';
    }

    // 2. 레벨 기반 보스 (강적)
    if (monsterLevel >= playerLevel + 5) {
      return 'boss';
    }

    // 3. 엘리트 몬스터 (12% 확률)
    if (monsterGrade == MonsterGrade.elite) {
      return 'elite';
    }

    // 4. 일반 전투 (Act별 분기)
    return _getBattleBgmForLevel(playerLevel);
  }

  /// 레벨에 따른 전투 BGM 파일명 반환 (Act별 분기)
  String _getBattleBgmForLevel(int playerLevel) {
    final act = getActForLevel(playerLevel);
    return switch (act) {
      StoryAct.act4 => 'battle_act4',
      StoryAct.act5 => 'battle_act5',
      _ => 'battle',
    };
  }

  /// 상태 리셋 (새 게임 시작 시)
  void reset() {
    _wasInBattleTask = false;
    _wasDead = false;
    _wasComplete = false;
    _lastSfxPlayTime.clear();
  }
}
