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

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

import 'package:flutter/services.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/utils/audio_util.dart';
import 'package:tone_snap/utils/log_util.dart';

class PlayerController extends GetxController {
  static PlayerController get to => Get.put(PlayerController());

  StreamSubscription<PlayerState>? _playerStateSubscription;
  StreamSubscription<Duration>? _durationSubscription;

  final _player = AudioPlayer();
  var filePath = '';
  var isPlaying = false.obs;
  var isCompleted = true.obs;
  var positionValue = 0.0.obs;
  var duration = const Duration().obs;
  var positionDuration = const Duration().obs;
  var isReady = false;

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

  @override
  void onClose() {
    _stopListening();
    _player.dispose();
    super.onClose();
  }

  Future<void> setFilePath(String filePath) async {
    if (!filePath.contains('assets') && !await _fileExists(filePath)) return;
    if (this.filePath != filePath) {
      this.filePath = filePath;
      try {
        isReady = false;
        if (filePath.contains('assets')) {
          duration.value = await _player.setAsset(filePath) ?? Duration.zero;
        } else {
          duration.value = await _player.setFilePath(filePath) ?? Duration.zero;
        }
        isReady = true;
      } on PlayerException catch (e) {
        LogUtil.e("Error code: ${e.code}");
        LogUtil.e("Error message: ${e.message}");
        BaseEasyLoading.toast("Error message: ${e.message}");
      } on PlayerInterruptedException catch (e) {
        LogUtil.e("Connection aborted: ${e.message}");
        BaseEasyLoading.toast("Connection aborted: ${e.message}");
      } catch (e) {
        LogUtil.e('An error occured: $e');
        BaseEasyLoading.toast('An error occured: $e');
      }
    }
  }

  /// 监听
  void _startListening() {
    _playerStateSubscription = _player.playerStateStream.listen((playerState) {
      switch (playerState.processingState) {
        case ProcessingState.idle:
          break;
        case ProcessingState.loading:
          break;
        case ProcessingState.buffering:
          break;
        case ProcessingState.ready:
          break;
        case ProcessingState.completed:
          isCompleted.value = true;
          _player.seek(Duration.zero);
          pausePlay();
          break;
      }
    });

    _durationSubscription = _player.positionStream.listen((position) {
      if (_player.duration != null) {
        duration.value = _player.duration!;
        positionDuration.value = position;
        positionValue.value = position.inMilliseconds.toDouble() / _player.duration!.inMilliseconds.toDouble();
      }
    }, onError: (Object e, StackTrace st) {
      if (e is PlatformException) {
        LogUtil.e('Error code: ${e.code}');
        LogUtil.e('Error message: ${e.message}');
        LogUtil.e('AudioSource index: ${e.details?['index']}');
        BaseEasyLoading.toast('Error message: ${e.message}');
      } else {
        LogUtil.e('An error occurred: $e');
        BaseEasyLoading.toast('An error occurred: $e');
      }
    });
  }

  void _stopListening() {
    _playerStateSubscription?.cancel();
    _playerStateSubscription = null;
    _durationSubscription?.cancel();
    _durationSubscription = null;
  }

  /// 开始播放
  Future<void> startPlay() async {
    if (!filePath.contains('assets') && !await _fileExists(filePath)) return;
    if (!isReady) {
      BaseEasyLoading.toast('Loading audio source');
      return;
    }
    _startListening();
    _player.play();
    isPlaying.value = true;
    isCompleted.value = false;
  }

  /// 暂停播放
  Future<void> pausePlay() async {
    await _player.pause();
    isPlaying.value = false;
    _stopListening();
  }

  /// 停止播放并释放资源
  Future<void> stopPlay() async {
    await _player.stop();
    _stopListening();
    _player.seek(Duration.zero);
    isPlaying.value = false;
    isCompleted.value = true;
    positionValue.value = 0.0;
    // duration.value = Duration.zero;
    positionDuration.value = Duration.zero;
  }

  String getDuration() {
    return printDuration(duration.value);
  }

  String getPositionDuration() {
    return printDuration(positionDuration.value);
  }

  /// 打印持续时间
  String printDuration(Duration duration) {
    String twoDigits(int n) => n.toString().padLeft(2, '0');
    final minutes = twoDigits(duration.inMinutes.remainder(60));
    final seconds = twoDigits(duration.inSeconds.remainder(60));
    return '$minutes:$seconds';
  }

  /// 判断文件是否存在
  Future<bool> _fileExists(String path) async {
    if (await File(path).exists()) {
      return true;
    } else {
      BaseEasyLoading.toast('Audio does not exist');
      return false;
    }
  }

  /// 设置声调
  Future<void> setPitch(double setPitch) async {
    await _player.setPitch(setPitch);
  }

  /// 设置声速
  Future<void> setSpeed(double speed) async {
    await _player.setSpeed(speed);
  }
}
