import 'package:flutter/foundation.dart' show debugPrint, kIsWeb;
import 'package:just_audio/just_audio.dart';

import 'package:askiineverdie/src/core/audio/sfx_channel_pool.dart';
import 'package:askiineverdie/src/core/storage/settings_repository.dart';

/// 게임 오디오 서비스
///
/// BGM과 SFX를 관리하며, 설정과 연동하여 볼륨을 조절합니다.
/// 웹/WASM 환경에서는 제한적으로 작동할 수 있습니다.
///
/// 채널 구조:
/// - BGM: 단일 플레이어 (루프 재생)
/// - Player SFX: 플레이어 이펙트 (공격, 스킬, 아이템 등)
/// - Monster SFX: 몬스터 이펙트 (몬스터 공격 = 플레이어 피격)
class AudioService {
  AudioService({SettingsRepository? settingsRepository})
      : _settingsRepository = settingsRepository ?? SettingsRepository();

  final SettingsRepository _settingsRepository;

  // BGM 플레이어
  AudioPlayer? _bgmPlayer;

  // SFX 채널 풀 (채널별 분리, 완료 보장)
  SfxChannelPool? _playerSfxPool;
  SfxChannelPool? _monsterSfxPool;

  // 채널별 풀 크기
  static const int _playerPoolSize = 4;
  static const int _monsterPoolSize = 3;

  // 현재 볼륨
  double _bgmVolume = 0.7;
  double _sfxVolume = 0.8;

  // 현재 재생 중인 BGM
  String? _currentBgm;

  // 초기화 여부
  bool _initialized = false;

  // 초기화 실패 여부 (WASM 등에서 오디오 지원 안됨)
  bool _initFailed = false;

  // 웹에서 사용자 상호작용 대기 중인 BGM (자동재생 정책 대응)
  String? _pendingBgm;

  // 사용자 상호작용 발생 여부 (웹 자동재생 정책 우회용)
  bool _userInteracted = false;

  // 오디오 일시정지 상태 (앱 백그라운드 시)
  bool _isPaused = false;

  /// 서비스 초기화
  Future<void> init() async {
    if (_initialized || _initFailed) return;

    try {
      // 설정에서 볼륨 불러오기
      _bgmVolume = await _settingsRepository.loadBgmVolume();
      _sfxVolume = await _settingsRepository.loadSfxVolume();

      // BGM 플레이어 초기화
      _bgmPlayer = AudioPlayer();
      await _bgmPlayer!.setLoopMode(LoopMode.one);
      await _bgmPlayer!.setVolume(_bgmVolume);

      // SFX 채널 풀 초기화 (채널별 분리)
      _playerSfxPool = SfxChannelPool(
        name: 'Player',
        poolSize: _playerPoolSize,
        volume: _sfxVolume,
      );
      await _playerSfxPool!.init();

      _monsterSfxPool = SfxChannelPool(
        name: 'Monster',
        poolSize: _monsterPoolSize,
        volume: _sfxVolume,
      );
      await _monsterSfxPool!.init();

      _initialized = true;

      // 모바일/데스크톱에서는 자동재생 제한 없음
      if (!kIsWeb) {
        _userInteracted = true;
      } else {
        debugPrint('[AudioService] Initialized on Web platform');
      }
    } catch (e) {
      _initFailed = true;
      debugPrint('[AudioService] Init failed (likely WASM): $e');
    }
  }

  /// BGM 재생
  ///
  /// [name]은 audio/bgm/ 폴더 내 파일명 (확장자 제외)
  /// 예: playBgm('battle') → audio/bgm/battle.mp3
  ///
  /// 웹에서 사용자 상호작용 없이 호출되면 대기 상태로 저장되고,
  /// 다음 SFX 재생 시 함께 시작됩니다.
  Future<void> playBgm(String name) async {
    if (_initFailed) return; // 초기화 실패 시 무시
    if (_isPaused) return; // 일시정지 상태면 무시
    if (!_initialized) await init();
    if (_initFailed || !_initialized) return;
    if (_currentBgm == name) return; // 이미 재생 중

    try {
      await _bgmPlayer!.setAsset('audio/bgm/$name.mp3');
      await _bgmPlayer!.play();
      _currentBgm = name;
      _pendingBgm = null;
      _userInteracted = true; // 재생 성공 → 상호작용 확인됨
      debugPrint('[AudioService] Playing BGM: $name');
    } catch (e) {
      // 웹 자동재생 정책으로 실패 시 대기 상태로 저장
      if (kIsWeb && e.toString().contains('NotAllowedError')) {
        _pendingBgm = name;
        debugPrint('[AudioService] BGM $name pending (waiting for user interaction)');
      } else {
        debugPrint('[AudioService] Failed to play BGM $name: $e');
      }
      _currentBgm = null;
    }
  }

  /// BGM 정지
  Future<void> stopBgm() async {
    if (!_initialized) return;

    await _bgmPlayer!.stop();
    _currentBgm = null;
  }

  /// BGM 일시정지
  Future<void> pauseBgm() async {
    if (!_initialized) return;
    await _bgmPlayer!.pause();
  }

  /// BGM 재개
  Future<void> resumeBgm() async {
    if (!_initialized) return;
    if (_currentBgm != null) {
      await _bgmPlayer!.play();
    }
  }

  /// 전체 오디오 일시정지 (앱 백그라운드 시)
  ///
  /// BGM을 정지하고, 새로운 재생 요청을 무시합니다.
  Future<void> pauseAll() async {
    _isPaused = true;
    if (!_initialized) return;

    // BGM 정지 및 상태 초기화
    await _bgmPlayer?.stop();
    _currentBgm = null;

    // SFX 채널 풀은 자동 완료되므로 별도 정지 불필요
    // (새로운 재생 요청만 _isPaused로 차단)

    debugPrint('[AudioService] All audio paused');
  }

  /// 전체 오디오 재개 (앱 포그라운드 복귀 시)
  ///
  /// 일시정지 상태를 해제하고 이전 BGM을 재개합니다.
  Future<void> resumeAll() async {
    _isPaused = false;
    debugPrint('[AudioService] Audio resumed');
  }

  /// 플레이어 이펙트 SFX 재생
  ///
  /// [name]은 audio/sfx/ 폴더 내 파일명 (확장자 제외)
  /// 예: playPlayerSfx('attack') → audio/sfx/attack.mp3
  ///
  /// 대기열 기반으로 모든 사운드의 완전 재생을 보장합니다.
  Future<void> playPlayerSfx(String name) async {
    if (_initFailed) return;
    if (_isPaused) return;
    if (!_initialized) await init();
    if (_initFailed || !_initialized) return;

    // 웹에서 대기 중인 BGM 재생 시도
    _tryPlayPendingBgm();

    await _playerSfxPool?.play('audio/sfx/$name.mp3');
  }

  /// 몬스터 이펙트 SFX 재생
  ///
  /// [name]은 audio/sfx/ 폴더 내 파일명 (확장자 제외)
  /// 예: playMonsterSfx('hit') → audio/sfx/hit.mp3
  ///
  /// 대기열 기반으로 모든 사운드의 완전 재생을 보장합니다.
  Future<void> playMonsterSfx(String name) async {
    if (_initFailed) return;
    if (_isPaused) return;
    if (!_initialized) await init();
    if (_initFailed || !_initialized) return;

    // 웹에서 대기 중인 BGM 재생 시도
    _tryPlayPendingBgm();

    await _monsterSfxPool?.play('audio/sfx/$name.mp3');
  }

  /// 웹에서 대기 중인 BGM 재생 시도 (사용자 상호작용 발생 시)
  void _tryPlayPendingBgm() {
    if (!_userInteracted && _pendingBgm != null) {
      _userInteracted = true;
      final pending = _pendingBgm;
      _pendingBgm = null;
      playBgm(pending!);
    }
  }

  /// SFX 재생 (레거시 호환)
  ///
  /// [name]은 audio/sfx/ 폴더 내 파일명 (확장자 제외)
  /// 예: playSfx('attack') → audio/sfx/attack.mp3
  ///
  /// @deprecated playPlayerSfx 또는 playMonsterSfx를 사용하세요.
  Future<void> playSfx(String name) => playPlayerSfx(name);

  /// BGM 볼륨 설정 (0.0 ~ 1.0)
  Future<void> setBgmVolume(double volume) async {
    _bgmVolume = volume.clamp(0.0, 1.0);
    if (_initialized && _bgmPlayer != null) {
      await _bgmPlayer!.setVolume(_bgmVolume);
    }
    await _settingsRepository.saveBgmVolume(_bgmVolume);
  }

  /// SFX 볼륨 설정 (0.0 ~ 1.0)
  ///
  /// 모든 SFX 채널 (플레이어, 몬스터)에 동시 적용됩니다.
  Future<void> setSfxVolume(double volume) async {
    _sfxVolume = volume.clamp(0.0, 1.0);
    if (_initialized) {
      await _playerSfxPool?.setVolume(_sfxVolume);
      await _monsterSfxPool?.setVolume(_sfxVolume);
    }
    await _settingsRepository.saveSfxVolume(_sfxVolume);
  }

  /// 현재 BGM 볼륨
  double get bgmVolume => _bgmVolume;

  /// 현재 SFX 볼륨
  double get sfxVolume => _sfxVolume;

  /// 현재 재생 중인 BGM
  String? get currentBgm => _currentBgm;

  /// 사용자 상호작용 발생 알림 (웹 자동재생 정책 우회)
  ///
  /// 버튼 클릭 등 사용자 상호작용 시 호출하면
  /// 대기 중인 BGM이 재생됩니다.
  Future<void> notifyUserInteraction() async {
    if (_userInteracted) return;
    _userInteracted = true;

    if (_pendingBgm != null) {
      final pending = _pendingBgm;
      _pendingBgm = null;
      await playBgm(pending!);
    }
  }

  /// 서비스 정리
  Future<void> dispose() async {
    await _bgmPlayer?.dispose();
    await _playerSfxPool?.dispose();
    await _monsterSfxPool?.dispose();
    _initialized = false;
  }
}

/// BGM 타입 열거형
enum BgmType {
  /// 타이틀 화면 BGM
  title,

  /// 마을/상점 BGM
  town,

  /// 일반 전투 BGM
  battle,

  /// 보스 전투 BGM
  boss,

  /// 레벨업/퀘스트 완료 팡파레
  victory,
}

/// SFX 타입 열거형
enum SfxType {
  /// 공격
  attack,

  /// 피격
  hit,

  /// 스킬 사용
  skill,

  /// 아이템 획득
  item,

  /// UI 클릭
  click,

  /// 레벨업
  levelUp,

  /// 퀘스트 완료
  questComplete,
}

/// BgmType을 파일명으로 변환
extension BgmTypeExtension on BgmType {
  String get fileName => name;
}

/// SfxType을 파일명으로 변환
extension SfxTypeExtension on SfxType {
  String get fileName => switch (this) {
    SfxType.attack => 'attack',
    SfxType.hit => 'hit',
    SfxType.skill => 'skill',
    SfxType.item => 'item',
    SfxType.click => 'click',
    SfxType.levelUp => 'level_up',
    SfxType.questComplete => 'quest_complete',
  };
}
