import 'package:ambito/src/entity/entities.dart';
import 'package:ambito/src/entity/lists/list_display.dart';
import 'package:ambito/src/entity/lists/list_repository.dart';
import 'package:ambito/src/entity/measure/category/measure_category.dart';
import 'package:ambito/src/entity/measure/complete/measure_complete.dart';
import 'package:ambito/src/entity/measure/measure_grouping.dart';
import 'package:ambito/src/entity/measure/months/measure_months.dart';
import 'package:ambito/src/entity/measure/types_details/measure_types_details_repository.dart';
import 'package:ambito/src/extensions/extensions.dart';
import 'package:ambito/src/packages/ambito_db/base_db.dart';
import 'package:isar/isar.dart';

import '../../consts/consts.dart';
import '../../packages/ambito_notifier/notifier/filter_notifier.dart';
import '../../widgets/form/fields/field_dropdown.dart';
import 'details/measure_details_repository.dart';
import 'group/measure_group.dart';

class MeasureRepository extends BaseDB {
  @override
  IsarCollection collection = isar.measureTypes;

  putMeasureGroups(MeasureGrouping mg) {
    isar.write((isar) {
      isar.measureGroupings.put(mg);
    });
  }

  MeasureTypes? getTypeByName(String name) {
    return isar.measureTypes.where().measureTypeEqualTo(name).findFirst();
  }

  Map<String, int> getTypesCounterByCategory(String category) {
    final counter = <String, int>{};

    /*final allMeasures = isar.measureGroups.where().findAll();

    for (final measure in allMeasures) {
      if (measure.categories?.isEmpty ?? true || measure.type == null) continue;

      final typeName = measure.type!.value;
      if (typeName == null) continue;

      final hasCategory = measure.categories!.any((cat) =>
          cat.value?.toLowerCase().replaceUmlauts() == category.toLowerCase());

      if (hasCategory) {
        counter[typeName] = (counter[typeName] ?? 0) + 1;
      }
    }*/

    return counter;
  }

  Future<bool> getCategoriesGroupsAndTypes() async {
    final categoriesMap = <String, MeasureCategory>{};
    final groupsMap = <String, MeasureGroup>{};

    final autoIncrementCat = isar.measureCategorys.autoIncrement;
    final autoIncrementType = isar.measureGroups.autoIncrement;

    // Fetch all measures
    final List<MeasureTypes> allMeasures = isar.measureTypes.where().findAll();

    for (final MeasureTypes measure in allMeasures) {
      if (measure.measureCategory == null ||
          measure.measureCategory == null ||
          measure.measureCategory!.isEmpty) {
        continue;
      }

      // Process categories
      for (final cat in measure.measureCategory!) {
        final categoryName = cat.value;
        if (categoryName == null) continue;

        if (!categoriesMap.containsKey(categoryName)) {
          categoriesMap[categoryName] = MeasureCategory()
            ..id = autoIncrementCat()
            ..name = categoryName
            ..url = categoryName.toLowerCase().replaceUmlauts()
            ..image =
                'images/measure/category/${categoryName.toLowerCase().replaceUmlauts()}.jpg'
            ..description = 'Lorem ipsum dolor sit amet.'
            ..children = 1;
        } else {
          categoriesMap[categoryName]!.children++;
        }
        categoriesMap[categoryName]!.ids.add(measure.id);
      }

      // Process types
      final groupName = measure.measureGroup!.value;
      if (groupName == null) continue;

      if (!groupsMap.containsKey(groupName)) {
        groupsMap[groupName] = MeasureGroup()
          ..id = autoIncrementType()
          ..name = groupName
          ..url = groupName.toLowerCase().replaceUmlauts()
          ..description = measure.description ?? ''
          ..image =
              'images/measure/group/${groupName.toLowerCase().replaceUmlauts()}.jpg' // Add the appropriate image URL if available
          ..children = 1
          ..categories = measure.measureCategory!
              .map((item) =>
                  item.value!.toLowerCase().replaceUmlauts().toString())
              .toList();
      } else {
        groupsMap[groupName]!.categories.addAll(measure.measureCategory!
            .map(
                (item) => item.value!.toLowerCase().replaceUmlauts().toString())
            .toList());
        groupsMap[groupName]!.children++;
      }
      groupsMap[groupName]!.ids.add(measure.id);
    }

    isar.write((isar) {
      isar.measureCategorys.putAll(categoriesMap.values.toList());
      isar.measureGroups.putAll(groupsMap.values.toList());
    });
    return true;
  }

  Future<bool> buildLists() async {
    return true;
  }

  Future<bool> buildMeasureFilters() async {
    return true;
  }

  int getMeasureCount() {
    return isar.measureTypes.where().count();
  }

  List<MeasureTypes?> getByIds(List<int> ids) {
    return isar.measureTypes.getAll(ids);
  }

  List<MeasureTypes> getAllOrdered() {
    return isar.measureTypes.where().sortByMeasureType().findAll();
  }

  List<MeasureTypes> getAllOrderedByCategory(String category) {
    final lowerCaseCategory = category.toLowerCase().replaceUmlauts();
    final all = isar.measureTypes.where().sortByMeasureType().findAll();

    return all.where((mt) {
      return mt.measureCategory?.any((idcv) =>
              idcv.value?.toLowerCase().replaceUmlauts() ==
              lowerCaseCategory) ??
          false;
    }).toList();
  }

  List<MeasureCategory> getCategories() {
    return isar.measureCategorys.where().findAll();
  }

  List<int>? getIdsByCategory(String category) {
    if (category == '') {
      return isar.measureCategorys
          .where()
          .idsProperty()
          .findAll()
          .expand((x) => x)
          .toList();
    }
    return isar.measureCategorys
        .where()
        .urlEqualTo(category)
        .idsProperty()
        .findFirst();
  }

  List<int>? getIdsByGroup(String group) {
    if (group == '') {
      return isar.measureCategorys
          .where()
          .idsProperty()
          .findAll()
          .expand((x) => x)
          .toList();
    }
    return isar.measureGroups
        .where()
        .urlEqualTo(group)
        .idsProperty()
        .findFirst();
  }

  List<int>? getIdsByCategoryAndGroup(String category, String group) {
    Set<int> byCat = Set.from(getIdsByCategory(category) ?? []);
    Set<int> byGroup = Set.from(getIdsByGroup(group) ?? []);
    return byCat.intersection(byGroup).toList();
  }

  List<MeasureGroup> getGroupsByCategory(String category) {
    return isar.measureGroups
        .where()
        .categoriesElementContains(category)
        .findAll();
  }

  FieldDropdown getGroupDropDownByCategory(String category) {
    List<MeasureGroup> filterItems = getGroupsByCategory(category);

    return FieldDropdown(
      name: 'group',
      label: 'Maßnahmengruppe',
      filterValue: ambitoFilterNotifier.activeFilters['group'],
      onClear: () {
        ambitoFilterNotifier.removeFilter('group');
        ambitoFilterNotifier.removeFilter('type');
      },
      onSelected: (value) {
        ambitoFilterNotifier.removeFilter('type');
        ambitoFilterNotifier.setFilter(
          'group',
          value ?? '',
        );
      },
      entries: filterItems.map((item) => item.name!).toList(),
    );
  }

  FieldDropdown getTypeDropDownByCategoryAndGroup(
      String category, String group) {
    List<ListDisplay> filterItemsToShow =
        ListRepository().getTypesToDisplay(category, group);

    List<ListDisplay> filterItems = [];

    for (var filterItem in filterItemsToShow) {
      int childs = ListRepository()
          .getMeasuresToDisplay(
              category, group, filterItem.title!.toLowerCase().replaceUmlauts())
          .length;
      if (childs > 0) {
        filterItems.add(filterItem);
      }
    }

    return FieldDropdown(
      name: 'type',
      label: 'Maßnahmentyp',
      filterValue: ambitoFilterNotifier.activeFilters['type'],
      onClear: () {
        ambitoFilterNotifier.removeFilter('type');
      },
      onSelected: (value) {
        ambitoFilterNotifier.setFilter(
          'type',
          value ?? '',
        );
      },
      entries: filterItems.map((item) => item.title!).toList(),
    );
  }

  MeasureComplete? getMeasureCompleteByName(String name) {
    return isar.measureCompletes.where().nameEqualTo(name).findFirst();
  }

  void buildMeasureComplete() {
    List<MeasureComplete> allMeasureCompletes = [];

    List<MeasureGeneral> measuresGeneral =
        isar.measureGenerals.where().findAll();

    for (final measureGeneral in measuresGeneral) {
      Map<String, dynamic> combined = {'id': measureGeneral.id};

      // Fetch related details and types
      final measureDetails =
          MeasureDetailsRepository().getDetailsForMeasure(measureGeneral.name!);

      final MeasureTypes? measureType = MeasureRepository().getTypeByName(
          measureGeneral.measureType!.map((el) => el.value).first ?? '');
      final measureTypesDetails = MeasureTypesDetailsRepository()
          .getTypeDetailsForType(measureType?.measureType ?? '');
      // Save preferences and populate combined map
      prefs.setBool('extended_json', true).then((_) {
        _mergeToCombinedMap(combined, measureGeneral.toJson());
        _mergeToCombinedMap(combined, measureDetails?.toJson());
        _mergeToCombinedMap(combined, measureType?.toJson());
        _mergeToCombinedMap(combined, measureTypesDetails?.toJson());

        isar.write((isar) {
          isar.measureCompletes.put(MeasureComplete.fromJson(combined));
        });
      });
    }
  }

  void _mergeToCombinedMap(
      Map<String, dynamic> combined, Map<String, dynamic>? data) {
    data?.forEach((key, value) {
      if (key != 'id') {
        combined[key] = value;
      }
    });
  }

  void buildMeasureMonths() {
    List<MeasureComplete> allCompletes =
        isar.measureCompletes.where().findAll();
    List<MeasureMonths> measureMonths = [];

    for (final complete in allCompletes) {
      List<bool> apply = months
          .map((item) => complete.applyMonths?.contains(item) ?? false)
          .toList();
      List<bool> maint = months
          .map((item) => complete.maintenanceMonths?.contains(item) ?? false)
          .toList();
      final measureMonth = MeasureMonths()
        ..id = complete.id
        ..name = complete.name
        ..maintenanceList = maint
        ..applyList = apply;

      isar.write((isar) {
        isar.measureMonths.put(measureMonth);
      });
    }
  }
}
