import 'dart:async';
import 'dart:collection';

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

/// SFX 채널 풀 - 사운드 완료 보장 (핫 리로드 안전)
///
/// 대기열 기반으로 모든 사운드의 완전 재생을 보장합니다.
/// 사용 가능한 플레이어가 없으면 대기열에 추가하고,
/// 재생 완료 시 대기열의 다음 사운드를 자동 재생합니다.
///
/// 플레이어 인스턴스를 static으로 관리하여 핫 리로드에서도 안전합니다.
class SfxChannelPool {
  SfxChannelPool({required this.name, this.poolSize = 4, double volume = 0.8})
    : _volume = volume;

  /// 채널명 (디버그용)
  final String name;

  /// 풀 크기
  final int poolSize;

  /// 채널 볼륨
  double _volume;

  /// static 플레이어 저장소 (채널명 기반, 핫 리로드에서 유지)
  static final Map<String, List<AudioPlayer>> _staticPlayers = {};

  /// static busy 상태 (채널명 기반)
  static final Map<String, List<bool>> _staticBusy = {};

  /// static 초기화 완료 여부 (채널명 기반)
  static final Map<String, bool> _staticInitialized = {};

  /// static 초기화 진행 중 Completer (중복 초기화 방지)
  static final Map<String, Completer<void>?> _staticInitCompleters = {};

  /// 대기열 (재생 대기 중인 에셋 경로)
  final Queue<String> _pendingQueue = Queue();

  /// 현재 볼륨
  double get volume => _volume;

  /// 초기화 완료 여부
  bool get isInitialized => _staticInitialized[name] == true;

  /// 사용 가능한 플레이어 수
  int get availablePlayerCount => _staticPlayers[name]?.length ?? 0;

  /// 초기화
  Future<void> init() async {
    // 이미 초기화 완료됨
    if (_staticInitialized[name] == true) {
      return;
    }

    // 초기화 진행 중이면 완료 대기
    if (_staticInitCompleters[name] != null) {
      await _staticInitCompleters[name]!.future;
      return;
    }

    // 초기화 시작
    final completer = Completer<void>();
    _staticInitCompleters[name] = completer;

    try {
      // 이 채널의 플레이어 리스트 초기화
      _staticPlayers[name] ??= [];
      _staticBusy[name] ??= [];

      // 기존 플레이어가 있으면 재사용 (핫 리로드 대응)
      if (_staticPlayers[name]!.isNotEmpty) {
        debugPrint(
          '[SfxChannelPool:$name] Reusing ${_staticPlayers[name]!.length} existing players',
        );
        _staticInitialized[name] = true;
        completer.complete();
        return;
      }

      // 새 플레이어 순차적으로 생성 (지연 포함)
      var successCount = 0;
      for (var i = 0; i < poolSize; i++) {
        final player = await _createPlayerWithRetry(i);
        if (player != null) {
          _staticPlayers[name]!.add(player);
          _staticBusy[name]!.add(false);
          successCount++;
        }
      }

      if (successCount > 0) {
        _staticInitialized[name] = true;
        debugPrint(
          '[SfxChannelPool:$name] Initialized with $successCount/$poolSize players',
        );
      } else {
        debugPrint(
          '[SfxChannelPool:$name] All players failed - audio disabled',
        );
      }

      completer.complete();
    } catch (e) {
      debugPrint('[SfxChannelPool:$name] Init error: $e');
      completer.complete();
    } finally {
      _staticInitCompleters[name] = null;
    }
  }

  /// 플레이어 생성 (재시도 포함)
  Future<AudioPlayer?> _createPlayerWithRetry(int index) async {
    const maxRetries = 3;
    const baseDelay = Duration(milliseconds: 100);

    for (var attempt = 0; attempt < maxRetries; attempt++) {
      try {
        // 생성 전 지연 (첫 번째 시도에서도)
        if (attempt > 0 || index > 0) {
          await Future<void>.delayed(baseDelay * (attempt + 1));
        }

        final player = AudioPlayer();
        await player.setVolume(_volume);

        // 재생 완료 리스너 등록
        player.playerStateStream.listen(
          (state) {
            if (state.processingState == ProcessingState.completed) {
              _onPlayerComplete(_staticPlayers[name]!.indexOf(player));
            }
          },
          onError: (Object e) {
            debugPrint('[SfxChannelPool:$name] Stream error: $e');
          },
        );

        return player;
      } catch (e) {
        debugPrint(
          '[SfxChannelPool:$name] Player $index attempt ${attempt + 1} failed: $e',
        );
        if (attempt == maxRetries - 1) {
          return null;
        }
      }
    }
    return null;
  }

  /// 사운드 재생 (완료 보장)
  Future<void> play(String assetPath) async {
    // 초기화 안됐으면 초기화 시도
    if (!isInitialized) {
      await init();
    }

    // 플레이어가 없으면 무시
    final players = _staticPlayers[name];
    if (players == null || players.isEmpty) {
      return;
    }

    // 볼륨이 0이면 재생 안함
    if (_volume == 0) return;

    // 사용 가능한 플레이어 찾기
    final availableIndex = _findAvailablePlayer();

    if (availableIndex != -1) {
      // 즉시 재생
      await _playOnPlayer(availableIndex, assetPath);
    } else {
      // 대기열에 추가 (최대 10개로 제한)
      if (_pendingQueue.length < 10) {
        _pendingQueue.add(assetPath);
      }
    }
  }

  /// 볼륨 설정 (0.0 ~ 1.0)
  Future<void> setVolume(double volume) async {
    _volume = volume.clamp(0.0, 1.0);

    final players = _staticPlayers[name];
    if (players != null) {
      for (final player in players) {
        try {
          await player.setVolume(_volume);
        } catch (_) {}
      }
    }
  }

  /// 리소스 해제
  Future<void> dispose() async {
    final players = _staticPlayers[name];
    if (players != null) {
      for (final player in players) {
        try {
          await player.dispose();
        } catch (_) {}
      }
      players.clear();
    }

    _staticBusy[name]?.clear();
    _pendingQueue.clear();
    _staticInitialized[name] = false;
  }

  /// 사용 가능한 플레이어 인덱스 반환 (-1: 없음)
  int _findAvailablePlayer() {
    final busy = _staticBusy[name];
    if (busy == null) return -1;

    for (var i = 0; i < busy.length; i++) {
      if (!busy[i]) {
        return i;
      }
    }
    return -1;
  }

  /// 특정 플레이어에서 사운드 재생
  Future<void> _playOnPlayer(int index, String assetPath) async {
    final players = _staticPlayers[name];
    final busy = _staticBusy[name];

    if (players == null || busy == null) return;
    if (index < 0 || index >= players.length) return;

    final player = players[index];
    busy[index] = true;

    try {
      await player.stop();
      await player.setAsset(assetPath);
      await player.seek(Duration.zero);
      await player.play();
    } catch (e) {
      busy[index] = false;
      if (e.toString().contains('Unable to load asset')) {
        debugPrint('[SfxChannelPool:$name] Asset not found: $assetPath');
      }
    }
  }

  /// 플레이어 재생 완료 시 호출
  void _onPlayerComplete(int index) {
    final busy = _staticBusy[name];
    if (busy == null || index < 0 || index >= busy.length) return;

    busy[index] = false;

    if (_pendingQueue.isNotEmpty) {
      final nextAsset = _pendingQueue.removeFirst();
      _playOnPlayer(index, nextAsset);
    }
  }

  /// 모든 static 리소스 정리 (테스트용)
  static void resetAll() {
    for (final players in _staticPlayers.values) {
      for (final player in players) {
        try {
          player.dispose();
        } catch (_) {}
      }
    }
    _staticPlayers.clear();
    _staticBusy.clear();
    _staticInitialized.clear();
    _staticInitCompleters.clear();
  }
}
