import 'package:ambito/src/entity/entities.dart';
import 'package:ambito/src/entity/lists/list_display.dart';
import 'package:ambito/src/entity/lists/list_measure_single.dart';
import 'package:ambito/src/entity/lists/list_measure_type_group_category.dart';
import 'package:ambito/src/extensions/extensions.dart';
import 'package:isar/isar.dart';

import '../../consts/consts.dart';
import 'list_measure.dart';

class ListRepository {
  void putListMeasure(List<ListMeasure> listMeasures) {
    isar.write((isar) {
      isar.listMeasures.putAll(listMeasures);
    });
  }

  void buildTypeGroupCategoryList() {
    List<MeasureTypes> measures = isar.measureTypes.where().findAll();
    List<ListMeasureTypeGroupCategory> tgc = [];

    isar.write((isar) {
      isar.listMeasureTypeGroupCategorys.clear();
    });

    for (final measure in measures) {
      for (final cat in measure.measureCategory!) {
        tgc.add(
          ListMeasureTypeGroupCategory()
            ..id = isar.listMeasureTypeGroupCategorys.autoIncrement()
            ..description = measure.description
            ..measureType = measure.measureType
            ..measureTypeUrl =
                measure.measureType!.toLowerCase().replaceUmlauts()
            ..measureGroup = measure.measureGroup!.value
            ..measureGroupUrl =
                measure.measureGroup!.value!.toLowerCase().replaceUmlauts()
            ..measureCategory = cat.value
            ..measureCategoryUrl = cat.value!.toLowerCase().replaceUmlauts()
            ..files = measure.files,
        );
      }
    }
    isar.write((isar) {
      isar.listMeasureTypeGroupCategorys.putAll(tgc);
    });
  }

  List<ListMeasureTypeGroupCategory> getCategoriesByTypeAndGroup(
      String type, String group) {
    return isar.listMeasureTypeGroupCategorys
        .where()
        .group(
            (q) => q.measureTypeEqualTo(type).or().measureTypeUrlEqualTo(type))
        .and()
        .group((q2) =>
            q2.measureGroupEqualTo(group).or().measureGroupUrlEqualTo(group))
        .findAll();
  }

  int getGroupsCounterByCategory(String category) {
    return isar.listMeasureTypeGroupCategorys
        .where()
        .group((q) => q
            .measureCategoryEqualTo(category)
            .or()
            .measureCategoryUrlEqualTo(category))
        .distinctByMeasureGroup()
        .count();
  }

  List<ListMeasureTypeGroupCategory> getTypesByCategoryAndGroup(
      String category, String group) {
    return isar.listMeasureTypeGroupCategorys
        .where()
        .group((q) => q
            .measureCategoryEqualTo(category)
            .or()
            .measureCategoryUrlEqualTo(category))
        .and()
        .group((q2) =>
            q2.measureGroupEqualTo(group).or().measureGroupUrlEqualTo(group))
        .findAll();
  }

  List<ListDisplay> getGroupsToDisplay(String category) {
    final String categoryToSearch = category.toLowerCase().replaceUmlauts();

    return isar.listMeasureTypeGroupCategorys
        .where()
        .measureCategoryUrlEqualTo(categoryToSearch)
        .findAll()
        .map((item) => item.asListDisplay())
        .toList();
  }

  List<ListDisplay> getTypesToDisplay(String category, String group) {
    final String categoryToSearch = category.toLowerCase().replaceUmlauts();
    final String groupToSearch = group.toLowerCase().replaceUmlauts();

    return isar.listMeasureTypeGroupCategorys
        .where()
        .measureCategoryUrlEqualTo(categoryToSearch)
        .and()
        .measureGroupUrlEqualTo(groupToSearch)
        .findAll()
        .map((item) => item.asListDisplay())
        .toList();
  }

  List<ListDisplay> getMeasuresToDisplay(
    String category,
    String group,
    String type,
  ) {
    final String categoryToSearch = category.toLowerCase().replaceUmlauts();
    final String groupToSearch = group.toLowerCase().replaceUmlauts();
    final String typeToSearch = type.toLowerCase().replaceUmlauts();

    return isar.listMeasureSingles
        .where()
        .measureCategoryUrlEqualTo(categoryToSearch)
        .and()
        .measureGroupUrlEqualTo(groupToSearch)
        .and()
        .measureTypeUrlEqualTo(typeToSearch)
        .findAll()
        .map((item) => item.asListDisplay())
        .toList();
  }

  int getTypesCounterByCategoryAndGroup(String category, String group) {
    return isar.listMeasureTypeGroupCategorys
        .where()
        .group((q) => q
            .measureCategoryEqualTo(category)
            .or()
            .measureCategoryUrlEqualTo(category))
        .and()
        .group((q2) =>
            q2.measureGroupEqualTo(group).or().measureGroupUrlEqualTo(group))
        .count();
  }

  void buildListMeasureSingle() {
    List<MeasureGeneral> measuresAll = isar.measureGenerals.where().findAll();

    isar.write((isar) {
      isar.listMeasureSingles.clear();
    });

    for (final measure in measuresAll) {
      for (final measureType in measure.measureType!) {
        final MeasureTypes types = isar.measureTypes
            .where()
            .measureTypeEqualTo(measureType.value)
            .findFirst()!;

        final List<ListMeasureTypeGroupCategory> cats =
            getCategoriesByTypeAndGroup(
                types.measureType!, types.measureGroup!.value!);

        for (final cat in cats) {
          final ListMeasureSingle single = ListMeasureSingle()
            ..id = measure.id
            ..name = measure.name
            ..description = types.description
            ..measureCategory = cat.measureCategory
            ..measureCategoryUrl = cat.measureCategoryUrl
            ..measureGroup = cat.measureGroup
            ..measureGroupUrl = cat.measureGroupUrl
            ..measureType = cat.measureType
            ..measureTypeUrl = cat.measureTypeUrl
            ..files = measure.files ?? types.files;

          isar.write((isar) {
            isar.listMeasureSingles.put(single);
          });
        }
      }
    }
  }

  List<ListMeasureSingle> getMeasuresByCategory(
    String category,
  ) {
    return isar.listMeasureSingles
        .where()
        .measureCategoryUrlEqualTo(category)
        .or()
        .measureCategoryEqualTo(category)
        .findAll();
  }

  List<ListMeasureSingle> getMeasuresByCategoryAndGroup(
    String category,
    String group,
  ) {
    return isar.listMeasureSingles
        .where()
        .group(
          (q1) => q1
              .measureCategoryUrlEqualTo(category)
              .or()
              .measureCategoryEqualTo(category),
        )
        .and()
        .group(
          (q2) =>
              q2.measureGroupUrlEqualTo(group).or().measureGroupEqualTo(group),
        )
        .findAll();
  }

  List<ListMeasureSingle> getMeasuresByCategoryAndGroupAndType(
    String category,
    String group,
    String type,
  ) {
    return isar.listMeasureSingles
        .where()
        .group(
          (q1) => q1
              .measureCategoryUrlEqualTo(category)
              .or()
              .measureCategoryEqualTo(category),
        )
        .and()
        .group(
          (q2) =>
              q2.measureGroupUrlEqualTo(group).or().measureGroupEqualTo(group),
        )
        .and()
        .group(
          (q3) => q3.measureTypeUrlEqualTo(type).or().measureTypeEqualTo(type),
        )
        .findAll();
  }
}
