import 'dart:async';
import 'dart:developer';

import 'package:mnemo_cards/di/locator.dart';
import 'package:mnemo_cards/features/packs/pack_cache_manager.dart';
import 'package:mnemo_cards/features/packs/packs_api.dart';
import 'package:mnemo_cards/features/packs/preview_pack_holder.dart';
import 'package:mnemo_cards/main.dart';
import 'package:mnemo_cards/managers/repository/repository.dart';
import 'package:mnemo_cards/utils/iterable_helper.dart';
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
import 'package:rxdart/rxdart.dart';

import 'pack_holder.dart';

class PackManager {
  final Repository _repository;
  final PacksApi _packsApi;
  final PackHolder _packHolder;
  final PreviewPackHolder _previewPackHolder;
  final PackCacheManager _cacheManager;

  PackManager(
    this._repository,
    this._packsApi,
    this._packHolder,
    this._previewPackHolder,
    this._cacheManager,
  );

  Future<void> init() async {
    _packHolder.setPacks(await _cacheManager.loadAllPacks());

    // _repository.userStream.map((u) => u.packs).distinct().listen((packs) async {
    //   final savedPacks = await savedPacksIds;
    //   for (final p in packs) {
    //     if (savedPacks.contains(p)) {
    //       final loaded = await loadPackFromCache(p);
    //       if (loaded.cards.isEmpty) {
    //         await downloadPackById(p);
    //       }
    //     } else {
    //       await downloadPackById(p);
    //     }
    //   }
    // });
  }

  Stream<GetCardPackResponse> getCardPackStream(
    String id,
    bool isAvailable,
  ) async* {
    if (isAvailable) {
      try {
        yield await _cacheManager.loadPackFromCache(id);
      } catch (err) {
        yield GetCardPackResponse.loading();
        log('Cant load pack from cache, fetching pack', error: err);
        try {
          await locator.packUpdater.updatePackAndSaveImages(id);
          yield await _cacheManager.loadPackFromCache(id);
        } on Object catch (e, s) {
          log('Cant fetch pack', error: e, stackTrace: s);
        }
      }
    } else {
      yield GetCardPackResponse.loading();
      final buyDto = await _packsApi.getPackBuy(id).catchError((_) => null);
      if (buyDto != null) {
        yield buyDto;
      } else {
        log('Buy dto is null, fetching pack');
        try {
          await locator.packUpdater.updatePackAndSaveImages(id);
          yield await _cacheManager.loadPackFromCache(id);
        } on Object catch (e, s) {
          log('Cant fetch pack', error: e, stackTrace: s);
        }
      }
    }
    yield* _packHolder.asStream
        .map((event) =>
            event?.packsWithCards.firstWhereOrNull((p) => p.id == id))
        .whereNotNull();
  }

  Future<void> clearCache() async {
    _packHolder.clear();
    await _cacheManager.clearCache();
  }

  Stream<List<CardPackDto>?> get packsStream =>
      _packHolder.asStream.map((event) => event?.packsWithCards);

  Stream<List<CardPackPreviewDto>?> get packsPreviewStream =>
      _previewPackHolder.asStream
          .map((event) => event?.previewPacks)
          .whereNotNull()
          .distinct((prev, next) {
        if (prev.length != next.length) return false;
        for (int i = 0; i < prev.length; i++) {
          if (prev[i].isAvailable != next[i].isAvailable) return false;
          if (prev[i].id != next[i].id) return false;
          if (prev[i].version != next[i].version) return false;
          if (prev[i].price != next[i].price) return false;
        }
        return true;
      });
}
