import 'dart:async';

import 'package:flutter/services.dart';
import 'package:guru_utils/log/log.dart';
import 'package:guru_utils/quiver/cache/cache.dart';
import 'package:guru_utils/quiver/cache/map_cache.dart';

import 'package:soundpool/soundpool.dart';

part 'audio_bundle.dart';

/// Created by Haoyi on 2022/8/25
///
part 'audio_model.dart';

part 'sound_pool.dart';

typedef Stoppable = void Function();

class AudioEffector {
  static final AudioEffector instance = AudioEffector._();

  static int soundEffect = SoundEffect.on;

  AudioEffector._();

  final Map<AudioEffect, Audio> audios = {};

  final Map<String, AudioBundle> bundles = {};

  static void init() {}

  Future registerBundle(AudioBundle bundle) async {
    if (!bundles.containsKey(bundle.name)) {
      await bundle.load();
      bundles[bundle.name] = bundle;
      audios.addAll(bundle.audios);
    }
  }

  Future unregisterBundle(AudioBundle bundle) async {
    bundles.remove(bundle.name);
    final _audios = bundle.audios;
    audios.removeWhere((key, _) => _audios.containsKey(key));
    bundle.dispose();
  }

  void enable() {
    AudioEffector.soundEffect = SoundEffect.on;
  }

  void disable() {
    AudioEffector.soundEffect = SoundEffect.off;
  }

  void play(AudioEffect audio) async {
    _internalPlay(audio);
  }

  Future<Stoppable> startLoop(AudioEffect audio) {
    final control = _internalPlay(audio, -1);
    return Future.value(() {
      control.then((value) => value?.stop());
    });
  }

  Future<AudioStreamControl?> _internalPlay(AudioEffect audio, [int repeat = 0]) async {
    try {
      if (soundEffect == SoundEffect.off) {
        return null;
      }
      assert(
        audios.containsKey(audio),
        'Tried to play unregistered audio $audio',
      );
      return audios[audio]?.play(repeat);
    } catch (error, stacktrace) {
      Log.w("play error:$error");
    }
    return null;
  }
}
