import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../api/endpoints/likes.dart';
import '../library/library_providers.dart';

final likesApiProvider = FutureProvider<LikesApi>((ref) async {
  return LikesApi(await ref.watch(dioProvider.future));
});

class LikedIds {
  const LikedIds({
    required this.artists,
    required this.albums,
    required this.tracks,
  });
  final Set<String> artists;
  final Set<String> albums;
  final Set<String> tracks;

  bool has(LikeKind kind, String id) => switch (kind) {
        LikeKind.artist => artists.contains(id),
        LikeKind.album => albums.contains(id),
        LikeKind.track => tracks.contains(id),
      };
}

class LikedIdsController extends AsyncNotifier<LikedIds> {
  @override
  Future<LikedIds> build() async {
    final api = await ref.watch(likesApiProvider.future);
    final r = await api.ids();
    return LikedIds(artists: r.artists, albums: r.albums, tracks: r.tracks);
  }

  Future<void> toggle(LikeKind kind, String id) async {
    final api = await ref.read(likesApiProvider.future);
    final current = state.value ??
        const LikedIds(artists: {}, albums: {}, tracks: {});

    final isLiked = current.has(kind, id);
    final optimistic = _flip(current, kind, id);
    state = AsyncData(optimistic);

    try {
      if (isLiked) {
        await api.unlike(kind, id);
      } else {
        await api.like(kind, id);
      }
    } catch (e, st) {
      state = AsyncData(current);
      Error.throwWithStackTrace(e, st);
    }
  }

  LikedIds _flip(LikedIds before, LikeKind kind, String id) {
    Set<String> swap(Set<String> s) {
      final next = {...s};
      if (s.contains(id)) {
        next.remove(id);
      } else {
        next.add(id);
      }
      return next;
    }

    return switch (kind) {
      LikeKind.artist => LikedIds(
          artists: swap(before.artists),
          albums: before.albums,
          tracks: before.tracks,
        ),
      LikeKind.album => LikedIds(
          artists: before.artists,
          albums: swap(before.albums),
          tracks: before.tracks,
        ),
      LikeKind.track => LikedIds(
          artists: before.artists,
          albums: before.albums,
          tracks: swap(before.tracks),
        ),
    };
  }
}

final likedIdsProvider =
    AsyncNotifierProvider<LikedIdsController, LikedIds>(LikedIdsController.new);
