import 'dart:convert';

import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/model/customer_activity.dart';
import 'package:aitrainer_app/model/customer_exercise_device.dart';
import 'package:aitrainer_app/model/customer_property.dart';
import 'package:aitrainer_app/model/description.dart';
import 'package:aitrainer_app/model/evaluation.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_device.dart';
import 'package:aitrainer_app/model/exercise_plan_template.dart';
import 'package:aitrainer_app/model/exercise_tree.dart';
import 'package:aitrainer_app/model/exercise_tree_parents.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/faq.dart';
import 'package:aitrainer_app/model/product.dart';
import 'package:aitrainer_app/model/property.dart';
import 'package:aitrainer_app/model/purchase.dart';
import 'package:aitrainer_app/model/split_test.dart';
import 'package:aitrainer_app/model/training_plan.dart';
import 'package:aitrainer_app/model/tutorial.dart';
import 'package:aitrainer_app/service/api.dart';
import 'package:aitrainer_app/service/exercise_type_service.dart';
import 'package:aitrainer_app/util/not_found_exception.dart';

import '../model/sport.dart';
import 'customer_service.dart';
import 'exercise_tree_service.dart';

class PackageApi {
  final APIClient _client = new APIClient();

  Future<void> getPackage() async {
    late List<ExerciseTree> exerciseTree;
    late List<ExerciseTreeParents> exerciseTreeParents;
    final body = await _client.get("app_package/", "");

    final List<String> models = body.split("|||");
    await Future.forEach(models, (elem) async {
      final String element = elem as String;
      final List<String> headRecord = element.split("***");
      final Iterable json = jsonDecode(headRecord[1]);
      if (headRecord[0] == "ExerciseDevice") {
        final List<ExerciseDevice> devices = json.map((device) => ExerciseDevice.fromJson(device)).toList();
        Cache().setDevices(devices);
      } else if (headRecord[0] == "Product") {
        final List<Product> products = json.map((product) => Product.fromJson(product)).toList();
        Cache().setProducts(products);
      } else if (headRecord[0] == "Property") {
        final List<Property> properties = json.map((property) => Property.fromJson(property)).toList();
        Cache().setProperties(properties);
      } else if (headRecord[0] == "ExerciseTree") {
        exerciseTree = json.map((exerciseTree) => ExerciseTree.fromJson(exerciseTree)).toList();
      } else if (headRecord[0] == "ExerciseType") {
        final List<ExerciseType> exerciseTypes = json.map((exerciseType) => ExerciseType.fromJson(exerciseType)).toList();
        await Future.forEach(exerciseTypes, (elem) async {
          final ExerciseType exerciseType = elem as ExerciseType;
          exerciseType.imageUrl = await ExerciseTypeApi().buildImage(exerciseType.imageUrl, exerciseType.exerciseTypeId);
        });
        Cache().setExerciseTypes(exerciseTypes);
      } else if (headRecord[0] == "ExerciseAbility") {
      } else if (headRecord[0] == "ExercisePlanTemplate") {
        final List<ExercisePlanTemplate> exercisePlanTemplates =
            json.map((exercisePlanTemplate) => ExercisePlanTemplate.fromJson(exercisePlanTemplate)).toList();
        Cache().setExercisePlanTemplates(exercisePlanTemplates);
      } else if (headRecord[0] == "ExerciseTreeParents") {
        exerciseTreeParents = json.map((exerciseTreeParent) => ExerciseTreeParents.fromJson(exerciseTreeParent)).toList();
      } else if (headRecord[0] == "Evaluation") {
        final List<Evaluation> evaluations = json.map((evaluation) => Evaluation.fromJson(evaluation)).toList();
        Cache().evaluations = evaluations;
      } else if (headRecord[0] == "Sport") {
        final List<Sport> sports = json.map((sport) => Sport.fromJson(sport)).toList();
        Cache().setSports(sports);
      } else if (headRecord[0] == "Tutorial") {
        final Iterable json = jsonDecode(headRecord[1]);
        final List<Tutorial> tutorials = json.map((tutorial) => Tutorial.fromJson(tutorial)).toList();

        Cache().setTutorials(tutorials);
      } else if (headRecord[0] == "Description") {
        final Iterable json = jsonDecode(headRecord[1]);
        final List<Description>? descriptions = json.map((description) => Description.fromJson(description)).toList();
        //print("Description: $descriptions");
        Cache().setDescriptions(descriptions);
      } else if (headRecord[0] == "Faq") {
        final Iterable json = jsonDecode(headRecord[1]);
        final List<Faq>? faqs = json.map((faq) => Faq.fromJson(faq)).toList();
        //print("Faq: $faqs");
        Cache().setFaqs(faqs);
      } else if (headRecord[0] == "TrainingPlan") {
        final Iterable json = jsonDecode(headRecord[1]);
        final List<TrainingPlan>? plans = json.map((plan) => TrainingPlan.fromJson(plan)).toList();

        List<TrainingPlan> activePlans = [];
        if (plans != null) {
          plans.forEach((element) {
            if (element.active) {
              activePlans.add(element);
            }
          });
        }
        Cache().setTrainingPlans(activePlans);
      } else if (headRecord[0] == "SplitTests") {
        final Iterable json = jsonDecode(headRecord[1]);
        final List<SplitTest>? tests = json.map((test) => SplitTest.fromJson(test)).toList();
        //print("A/B tests: $tests");
        Cache().setSplitTests(tests);
      }
    });

    exerciseTree = this.getExerciseTreeParents(exerciseTree, exerciseTreeParents);

    await Future.forEach(exerciseTree, (element) async {
      ExerciseTree tree = element as ExerciseTree;
      tree.imageUrl = await ExerciseTreeApi().buildImage(tree.imageUrl, tree.treeId);
    });
    //print("tree: $exerciseTree");
    Cache().setExerciseTree(exerciseTree);

    return;
  }

  List<ExerciseTree> getExerciseTreeParents(final List<ExerciseTree> exerciseTree, final List<ExerciseTreeParents> exerciseTreeParents) {
    List<ExerciseTree> copyList = ExerciseTreeApi().copyList(exerciseTree);

    int treeIndex = 0;
    copyList.forEach((element) async {
      int index = 0;
      exerciseTreeParents.forEach((parent) {
        if (parent.exerciseTreeChildId == element.treeId) {
          if (index > 0) {
            ExerciseTree newElement = element.copy(parent.exerciseTreeParentId);
            newElement.sort = parent.sort;
            exerciseTree.add(newElement);
          } else {
            element.parentId = parent.exerciseTreeParentId;
            element.sort = parent.sort;
            exerciseTree[treeIndex].parentId = parent.exerciseTreeParentId;
            exerciseTree[treeIndex].sort = parent.sort;
          }
          index++;
        }
      });

      treeIndex++;
    });

    return exerciseTree;
  }

  Future<void> getCustomerPackage(int customerId) async {
    try {
      final body = await _client.get("app_customer_package/" + customerId.toString(), "");

      final List<String> models = body.split("|||");
      await Future.forEach(models, (elem) async {
        final String element = elem as String;
        final List<String> headRecord = element.split("***");
        //print("Class " + headRecord[0]);
        if (headRecord[0] == "Customer") {
          Customer customer = Customer.fromJson(jsonDecode(headRecord[1]));
          Cache().userLoggedIn = customer;
        } else if (headRecord[0] == "CustomerExerciseDevice") {
          final Iterable json = jsonDecode(headRecord[1]);
          final List<CustomerExerciseDevice> devices = json.map((device) => CustomerExerciseDevice.fromJson(device)).toList();
          Cache().setCustomerDevices(devices);
          // ToDo
        } else if (headRecord[0] == "Exercises") {
          final Iterable json = jsonDecode(headRecord[1]);
          final List<Exercise> exercises = json.map((exerciseType) => Exercise.fromJson(exerciseType)).toList();
          Cache().setExercises(exercises);
        } else if (headRecord[0] == "Purchase") {
          final Iterable json = jsonDecode(headRecord[1]);
          final List<Purchase> purchases = json.map((purchase) => Purchase.fromJson(purchase)).toList();
          Cache().setPurchases(purchases);
        } else if (headRecord[0] == "CustomerProperty") {
          final Iterable json = jsonDecode(headRecord[1]);
          final List<CustomerProperty> customerProperties = json.map((property) => CustomerProperty.fromJson(property)).toList();
          CustomerApi().initProperties(customerProperties);
        } else if (headRecord[0] == "ExerciseResult") {
          /*final Iterable json = jsonDecode(headRecord[1]);
           final List<ExerciseResult> exerciseResults = json.map((exerciseResult) {
            ExerciseResult item = ExerciseResult.fromJson(exerciseResult);
            return item;
          }).toList();
          // ToDo */
        } else if (headRecord[0] == "CustomerActivity") {
          final Iterable json = jsonDecode(headRecord[1]);
          final List<CustomerActivity> customerActivities = json.map((activity) => CustomerActivity.fromJson(activity)).toList();
          Cache().setCustomerActivities(customerActivities);
        }
      });
    } on NotFoundException catch (_) {
      throw Exception("Please log in");
    }
  }
}