// Author: fengshengxiong
// Date: 2024/5/30
// Description: 音乐播放器控制器

import 'dart:async';
import 'dart:io';

import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:get/get.dart';
import 'package:just_audio/just_audio.dart';
import 'package:tone_snap/components/base_easyloading.dart';
import 'package:tone_snap/data/api/music_api.dart';
import 'package:tone_snap/data/cache/music_cache_manager.dart';
import 'package:tone_snap/data/enum/play_mode.dart';
import 'package:tone_snap/data/models/music_model.dart';
import 'package:tone_snap/data/models/player_model.dart';
import 'package:tone_snap/data/storage/music_box.dart';
import 'package:tone_snap/data/storage/offline_box.dart';
import 'package:tone_snap/modules/sideb/music_bar/music_bar.dart';
import 'package:tone_snap/routes/app_routes.dart';
import 'package:tone_snap/utils/audio_util.dart';
import 'package:tone_snap/utils/log_util.dart';
import 'package:tone_snap/utils/num_util.dart';
import 'package:tone_snap/utils/obj_util.dart';

class MusicPlayerController extends GetxController {
  static MusicPlayerController get to => Get.put(MusicPlayerController(), permanent: true);
  final _player = AudioPlayer();
  StreamSubscription<Duration>? _bufferedSubscription;
  StreamSubscription<Duration?>? _durationSubscription;
  StreamSubscription<Duration>? _positionSubscription;
  StreamSubscription<PlayerState>? _playerStateSubscription;

  /// 总时长、已播放的时长、缓冲时长
  var totalDuration = Duration.zero.obs;
  var positionDuration = Duration.zero.obs;
  var bufferedDuration = Duration.zero.obs;

  /// 缓存管理器
  // final _cacheManager = DefaultCacheManager();
  final _cacheManager = MusicCacheManager.instance;

  /// 是否正在播放
  var isPlaying = false.obs;

  /// 播放器处理状态
  var processingState = ProcessingState.idle.obs;

  /// _player.seek(Duration.zero) 时，这可能会导致播放状态再次变为 completed。
  /// 为了避免这种情况，在处理 completed 状态时添加一个标志位，确保在处理完成状态时不会重复触发
  /// 是否已经处理过 completed 状态
  var _isCompletedHandled = false;

  /// 拖动开始时是否是播放状态
  var _seekFrontPlaying = true;

  /// 播放模式，默认列表循环
  var playMode = MusicBox().getPlayMode().obs;
  var _playModeIndex = 0;

  /// 播放历史 videoId 集合
  /// 随机播放切换到上一首时，从历史记录中取出上一个播放的 videoId
  final List<String> _playHistory = [];

  /// 播放列表
  var playlist = <Rx<MusicModel>>[].obs;

  /// 当前播放的歌曲索引
  var currentIndex = 0.obs;

  @override
  void onInit() {
    super.onInit();
    AudioUtil.configAudioSession();
  }

  @override
  void onClose() {
    MusicBar().hide();
    _cancelListening();
    _player.dispose();
    super.onClose();
  }

  void playMusic(String? videoId, {List<MusicModel>? playList, bool isCurrentPlaylist = false}) {
    if (videoId == null) return;
    if (!isCurrentPlaylist) {
      if (playList == null || playList.isEmpty) return;
      _playHistory.clear();
      playlist.value = playList.map((e) => e.obs).toList();
    }
    Rx<MusicModel>? model = playlist.firstWhereOrNull((e) => e.value.videoId == videoId);
    currentIndex.value = model != null ? playlist.indexOf(model) : 0;
    _startPlay();
  }

  Rx<MusicModel>? getMusicModel() {
    return playlist.isNotEmpty ? playlist[currentIndex.value] : null;
  }

  /// 播放歌曲
  Future<void> _startPlay() async {
    if (playlist.isNotEmpty) {
      resetPlaybackStatus();
      Get.currentRoute == AppRoutes.playPage ? MusicBar().hide() : MusicBar().show();
      try {
        MusicModel? model = OfflineBox().getList().firstWhereOrNull((e) => e.videoId == getMusicModel()!.value.videoId!);
        if (model != null && ObjUtil.isNotEmpty(model.localPath)) {
          // 有下载
          LogUtil.d('读取下载路径=${model.localPath}');
          if (!await File(model.localPath!).exists()) {
            BaseEasyLoading.toast('file does not exist');
            return;
          }
          await _player.setFilePath(model.localPath!);
        } else {
          // 无下载
          FileInfo? fileInfo = await MusicCacheManager.checkCache(getMusicModel()!.value.videoId!);
          if (fileInfo != null) {
            // 有缓存
            LogUtil.d('读取缓存路径=${fileInfo.file.path}');
            // 如果有缓存，使用缓存文件
            await _player.setFilePath(fileInfo.file.path);
          } else {
            // 无缓存
            final url = await _getMusicUrl();
            if (ObjUtil.isEmpty(url)) {
              return;
            }
            await _player.setUrl(url!);
            // 同时启动缓存下载
            _cacheManager.downloadFile(url, key: MusicCacheManager.getCacheKey(getMusicModel()!.value.videoId!)).then((fileInfo) {
              LogUtil.d('缓存下载路径=${fileInfo.file.path}');
            });
          }
        }
        _cancelListening();
        _addListening();
        _player.play();
      } catch (e) {
        LogUtil.e('Play failed: $e');
        BaseEasyLoading.toast('Play failed');
      }
    }
  }

  /// 获取当前歌曲的播放 url
  Future<String?> _getMusicUrl() async {
    PlayerModel? model = await MusicApi.player(videoId: playlist[currentIndex.value].value.videoId);
    if (model != null && model.streamingData != null) {
      var formats = model.streamingData?.formats;
      if (formats != null && playlist.isNotEmpty) {
        return formats[0].url;
      }
    }
    return null;
  }

  /// 监听
  void _addListening() {
    _durationSubscription = _player.durationStream.listen((duration) {
      totalDuration.value = duration ?? Duration.zero;
    });

    _positionSubscription = _player.positionStream.listen((position) {
      int comparison = position.compareTo(totalDuration.value);
      if (comparison > 0) {
        positionDuration.value = totalDuration.value;
      } else {
        positionDuration.value = position;
      }
    });

    _bufferedSubscription = _player.bufferedPositionStream.listen((bufferedPosition) {
      int comparison = bufferedPosition.compareTo(totalDuration.value);
      if (comparison > 0) {
        bufferedDuration.value = totalDuration.value;
      } else {
        bufferedDuration.value = bufferedPosition;
      }
    });

    _playerStateSubscription = _player.playerStateStream.listen((playerState) {
      isPlaying.value = _player.playing;
      processingState.value = playerState.processingState;
      switch (playerState.processingState) {
        case ProcessingState.idle:
          break;
        case ProcessingState.loading:
          break;
        case ProcessingState.buffering:
          break;
        case ProcessingState.ready:
          _isCompletedHandled = false;
          break;
        case ProcessingState.completed:
          if (!_isCompletedHandled) {
            _isCompletedHandled = true;
            _player.seek(Duration.zero);
            nextTrack(manualSwitch: false);
          }
          break;
      }
    });
  }

  /// 取消监听
  void _cancelListening() {
    _bufferedSubscription?.cancel();
    _durationSubscription?.cancel();
    _positionSubscription?.cancel();
    _playerStateSubscription?.cancel();
  }

  /// 将播放器的播放位置设置为指定的时间
  void seekToPosition(double value) {
    if (processingState.value == ProcessingState.ready) {
      positionDuration.value = Duration(seconds: value.toInt());
      _player.seek(positionDuration.value);
    }
  }

  /// 开始/结束拖动进度条
  Future<void> seekStartEnd(int value) async {
    if (processingState.value == ProcessingState.buffering || processingState.value == ProcessingState.ready) {
      if (value == 0) {
        _seekFrontPlaying = _player.playing;
        if (_player.playing) {
          _player.pause();
        }
      } else {
        // 拖动前如果是播放状态，拖动完成后恢复播放
        if (_seekFrontPlaying) {
          _player.play();
        }
      }
    }
  }

  /// 播放/暂停
  Future<void> playPause() async {
    if (_player.playing) {
      _player.pause();
    } else {
      if (processingState.value == ProcessingState.ready) {
        _player.play();
      }
    }
  }

  /// 上一首
  Future<void> previousTrack() async {
    if (playlist.length > 1) {
      switch(playMode.value) {
        case PlayMode.listLoop:
          currentIndex.value = (currentIndex.value - 1 + playlist.length) % playlist.length;
          _startPlay();
          break;
        case PlayMode.random:
          bool historyExist = false;
          for (var i = _playHistory.length - 1; i >= 0; --i) {
            var history = _playHistory[i];
            Rx<MusicModel>? model = playlist.firstWhereOrNull((e) => e.value.videoId == history);
            if (model != null) {
              currentIndex.value = playlist.indexOf(model);
              _playHistory.remove(history);
              historyExist = true;
              break;
            } else {
              _playHistory.remove(history);
            }
          }
          if (!historyExist) {
            currentIndex.value = _getRandomNumber();
          }
          _startPlay();
          break;
        case PlayMode.singleCycle:
          currentIndex.value = (currentIndex.value - 1 + playlist.length) % playlist.length;
          _startPlay();
          break;
      }
    }
  }

  /// 下一首
  Future<void> nextTrack({bool manualSwitch = true}) async {
    if (playlist.length > 1) {
      switch(playMode.value) {
        case PlayMode.listLoop:
          currentIndex.value = (currentIndex.value + 1) % playlist.length;
          _startPlay();
          break;
        case PlayMode.random:
          // 记录当前播放的索引
          _playHistory.add(getMusicModel()!.value.videoId!);
          currentIndex.value = _getRandomNumber();
          _startPlay();
          break;
        case PlayMode.singleCycle:
          if (manualSwitch) {
            currentIndex.value = (currentIndex.value + 1) % playlist.length;
            _startPlay();
          }
          break;
      }
    }
  }

  /// 在列表范围内生成一个不包括当前索引的随机数
  int _getRandomNumber() {
    return NumUtil.getRandomNumberExcludingCurrent(0, playlist.length, currentIndex.value);
  }

  /// 切换播放模式
  void switchPlayMode() {
    if (_playModeIndex >= PlayMode.values.length - 1) {
      _playModeIndex = 0;
    } else {
      _playModeIndex++;
    }
    playMode.value = PlayMode.values[_playModeIndex];
    MusicBox().putPlayMode(playMode.value);
    if (playMode.value == PlayMode.listLoop) {
      BaseEasyLoading.toast('List loop');
    }
    if (playMode.value == PlayMode.random) {
      BaseEasyLoading.toast('Shuffle Playback');
    }
    if (playMode.value == PlayMode.singleCycle) {
      BaseEasyLoading.toast('Single cycle');
    }
  }

  /// 重置播放状态
  Future<void> resetPlaybackStatus() async {
    await _player.stop();
    _player.seek(Duration.zero);
    totalDuration.value = Duration.zero;
    positionDuration.value = Duration.zero;
    bufferedDuration.value = Duration.zero;
  }
}
