
import 'package:audioplayers/audioplayers.dart' as audioplayers;
import 'package:flutter/foundation.dart';
import 'package:just_audio/just_audio.dart' as justaudio;

enum AudioWrapper_State {
  Playing,
  NotPlaying
}

class AudioWrapper {

  audioplayers.AudioPlayer _audioPlayer_AudioPlayer = audioplayers.AudioPlayer();
  justaudio.AudioPlayer _justAudio_AudioPlayer = justaudio.AudioPlayer();

  justaudio.AudioSource _convertSource_JustAudio(AudioWrapperSource source){
    if (source is AudioWrapperByteSource){
      return _ByteSource(source.bytes);
    } else if (source is AudioWrapperAssetSource){
      return justaudio.AudioSource.asset(source.assetPath);
    } else {
      throw Exception("Unknown source type");
    }
  }

  audioplayers.Source _convertSource_AudioPlayers(AudioWrapperSource source){
    if (source is AudioWrapperByteSource){
      return audioplayers.BytesSource(source.bytes);
    } else if (source is AudioWrapperAssetSource){
      return audioplayers.AssetSource(source.assetPath);
    } else {
      throw Exception("Unknown source type");
    }
  }

  Future<Duration?> play(AudioWrapperSource source) async {
    if (kIsWeb) {
      // Use just_audio

      justaudio.AudioSource audioSource = _convertSource_JustAudio(source);

      Duration? duration = await _justAudio_AudioPlayer.setAudioSource(audioSource);

      _justAudio_AudioPlayer.play();

      return duration;

    } else {
      // Use audioplayers

      audioplayers.Source audioSource = _convertSource_AudioPlayers(source);

      await _audioPlayer_AudioPlayer.play(audioSource);

      return await _audioPlayer_AudioPlayer.getDuration();
    }
  }

  void stop(){
    if (kIsWeb) {
      _justAudio_AudioPlayer.stop();
    } else {
      _audioPlayer_AudioPlayer.stop();
    }
  }

  AudioWrapper_State get state {
    if (kIsWeb) {
      if (_justAudio_AudioPlayer.playing){
        return AudioWrapper_State.Playing;
      } else {
        return AudioWrapper_State.NotPlaying;
      }
    } else {
      if (_audioPlayer_AudioPlayer.state == audioplayers.PlayerState.playing){
        return AudioWrapper_State.Playing;
      } else {
        return AudioWrapper_State.NotPlaying;
      }
    }
  }

}

class AudioWrapperSource {

}

class AudioWrapperByteSource extends AudioWrapperSource {

  Uint8List bytes = Uint8List(0);

  AudioWrapperByteSource(Uint8List bytes){
    this.bytes = bytes;
  }

}

class AudioWrapperAssetSource extends AudioWrapperSource {

  String assetPath = "";

  AudioWrapperAssetSource(String assetPath){
    this.assetPath = assetPath;
  }

}

class _ByteSource extends justaudio.StreamAudioSource {
  final List<int> bytes;
  _ByteSource(this.bytes);

  @override
  Future<justaudio.StreamAudioResponse> request([int? start, int? end]) async {
    start ??= 0;
    end ??= bytes.length;
    return justaudio.StreamAudioResponse(
      sourceLength: bytes.length,
      contentLength: end - start,
      offset: start,
      stream: Stream.value(bytes.sublist(start, end)),
      contentType: 'audio/mpeg',
    );
  }
}