import 'package:get/get.dart';

import 'package:f0ckapp/models/feed.dart';
import 'package:f0ckapp/models/item.dart';
import 'package:f0ckapp/services/api.dart';

const List<String> mediaTypes = ["alles", "image", "video", "audio"];
const List<String> mediaModes = ["sfw", "nsfw", "untagged", "all"];

class MediaController extends GetxController {
  final ApiService _api = Get.find<ApiService>();

  RxList<MediaItem> items = <MediaItem>[].obs;
  RxBool loading = false.obs;
  RxBool atEnd = false.obs;
  RxBool atStart = false.obs;

  RxInt typeIndex = 0.obs;
  RxInt modeIndex = 0.obs;
  RxInt random = 0.obs;
  Rxn<String> tag = Rxn<String>(null);

  void setTypeIndex(int idx) {
    typeIndex.value = idx;
    fetchInitial();
  }

  void setModeIndex(int idx) {
    modeIndex.value = idx;
    fetchInitial();
  }

  void setTag(String? newTag, {bool reload = true}) {
    tag.value = newTag;
    if (reload) {
      fetchInitial();
    }
  }

  Future<List<Favorite>?> toggleFavorite(
    MediaItem item,
    bool isFavorite,
  ) async {
    try {
      return await _api.toggleFavorite(item, isFavorite);
    } catch (e) {
      return [];
    }
  }

  Future<Feed?> _fetchItems({int? older, int? newer}) async {
    if (loading.value) return null;
    loading.value = true;
    try {
      return await _api.fetchItems(
        older: older,
        newer: newer,
        type: typeIndex.value,
        mode: modeIndex.value,
        random: random.value,
        tag: tag.value,
      );
    } catch (e) {
      Get.snackbar(
        'Fehler beim Laden',
        'Die Daten konnten nicht abgerufen werden. Wo Internet?',
        snackPosition: SnackPosition.BOTTOM,
      );
      return null;
    } finally {
      loading.value = false;
    }
  }

  Future<void> fetchInitial({int? id}) async {
    final result = await _fetchItems(older: id);
    if (result != null) {
      items.assignAll(result.items);
      atEnd.value = result.atEnd;
      atStart.value = result.atStart;
    }
  }

  Future<void> fetchMore() async {
    if (items.isEmpty || atEnd.value) return;
    final result = await _fetchItems(older: items.last.id);
    if (result != null) {
      final Set<int> existingIds = items.map((e) => e.id).toSet();
      final List<MediaItem> newItems = result.items
          .where((item) => !existingIds.contains(item.id))
          .toList();
      items.addAll(newItems);
      items.refresh();
      atEnd.value = result.atEnd;
    }
  }

  Future<int> fetchNewer() async {
    if (items.isEmpty || atStart.value) return 0;
    final oldLength = items.length;
    final result = await _fetchItems(newer: items.first.id);
    if (result != null) {
      final Set<int> existingIds = items.map((e) => e.id).toSet();
      final List<MediaItem> newItems = result.items
          .where((item) => !existingIds.contains(item.id))
          .toList();
      items.insertAll(0, newItems);
      items.refresh();
      atStart.value = result.atStart;
      return items.length - oldLength;
    }
    return 0;
  }

  Future<void> handleRefresh() async {
    if (loading.value) return;
    if (!atStart.value) {
      await fetchNewer();
    } else {
      await fetchInitial();
    }
  }

  Future<void> handleLoading() async {
    if (!loading.value && !atEnd.value) {
      await fetchMore();
    }
  }

  void toggleRandom() {
    random.value = random.value == 1 ? 0 : 1;
    fetchInitial();
  }

  bool get isRandomEnabled => random.value == 1;
}
