import 'dart:async';

import 'package:flutter/material.dart';
import 'package:get/get.dart';

import '../../../app/app.dart';
import 'multi_select_action.dart';
import 'multi_select_item.dart';

class MultiSelectController extends GetxController
    with StateMixin<List<MultiSelectItem<FilterOption>>>, MultiSelectActions<FilterOption>, ScrollMixin {
  // List<FilterOption> initialValues;
  // String modelCode;
  Timer? _debounce;

  FilterModel model;

  MultiSelectController(this.model);

  RxList<FilterOption> selectedValues = <FilterOption>[].obs;

  List<MultiSelectItem<FilterOption>> items = [];

  RxString searchKey = ''.obs;

  int page = 1;
  int itemPerPage = 20;
  bool getFirstData = false;
  RxBool lastPage = false.obs;
  @override
  void onInit() {
    searchKey.value = '';

    debugPrint('model.selectedOptions ${model.selectedOptions}');

    this.selectedValues.addAll(model.selectedOptions);
    update();

    getData();

    super.onInit();
  }

  Future<void> getData() async {
    await FilterApi.getOptions(page, itemPerPage, model, searchKey.value).then((result) {
      final bool emptyRepositories = result.isEmpty;
      if (!getFirstData && emptyRepositories) {
        change(null, status: RxStatus.empty());
      } else if (getFirstData && emptyRepositories) {
        lastPage.value = true;
      } else {
        getFirstData = true;

        // convert data
        var newItems = result.map((option) => MultiSelectItem<FilterOption>(option, option.label)).toList();
        debugPrint('newItems ${newItems.length}');
        for (var item in newItems) {
          item.selected = this.selectedValues.where((element) => element.id == item.value.id).isNotEmpty;
          items.add(item);
        }

        // check is last item
        if (items.length < itemPerPage) {
          lastPage.value = true;
        }
        change(items, status: RxStatus.success());
      }
      update();
    }, onError: (err) {
      change(null, status: RxStatus.error(err.toString()));
    });
  }

  @override
  Future<void> onEndScroll() async {
    debugPrint('onEndScroll ${lastPage.value}');
    if (!lastPage.value) {
      page += 1;
      await getData();
    }
  }

  @override
  Future<void> onTopScroll() async {
    debugPrint('onTopScroll');
  }

  void clearFilter(BuildContext ctx, void Function(List<FilterOption>)? onClear) {
    debugPrint('clearFilter');

    for (int i = 0; i < items.length; i++) {
      if (selectedValues.contains(items[i].value)) {
        items[i].selected = false;
      }
    }
    selectedValues.clear();

    this.onClearTap(ctx, selectedValues, onClear);

    update();
  }

  Future<void> onSearchChanged(String val) async {
    getFirstData = false;
    page = 1;

    searchKey.value = val;

    if (_debounce?.isActive ?? false) _debounce!.cancel();
    _debounce = Timer(const Duration(milliseconds: 600), () {
      items.clear();
      change(items, status: RxStatus.loading());
      getData();
      update();
    });
  }

  void onListBoxListTileChanged(
      MultiSelectItem<FilterOption> item, void Function(List<FilterOption>)? onSelectionChanged, checked) {
    debugPrint('onListBoxListTileChanged');

    if (checked) {
      item.selected = true;
      selectedValues.add(item.value);
    } else {
      item.selected = false;
      selectedValues.removeWhere((e) => e.id == item.value.id);
    }

    selectedValues.refresh();

    if (onSelectionChanged != null) {
      onSelectionChanged(selectedValues);
    }

    update();
  }

  void onConfirmSelection(BuildContext context, void Function(List<FilterOption>) onConfirm) {
    onConfirmTap(context, selectedValues, onConfirm);
    update();
  }
}
