import 'dart:collection';

import 'package:workouttest_util/model/cache.dart';
import 'package:workouttest_util/model/customer.dart';
import 'package:workouttest_util/model/customer_property.dart';
import 'package:workouttest_util/model/property.dart';
import 'package:workouttest_util/model/purchase.dart';
import 'package:workouttest_util/model/sport.dart';
import 'package:workouttest_util/repository/property_repository.dart';
import 'package:workouttest_util/service/customer_service.dart';
import 'package:workouttest_util/util/logging.dart';
import 'package:workouttest_util/service/purchase_service.dart';
import 'package:workouttest_util/util/enums.dart';

class GenderItem {
  GenderItem(this.dbValue, this.name);
  final String dbValue;
  String name;
}

class CustomerRepository with Logging {
  Customer? customer;
  Customer? _trainee;
  List<Customer>? _trainees;
  List<CustomerProperty>? _properties;
  //List<CustomerProperty>? _allCustomerProperties;
  final PropertyRepository propertyRepository = PropertyRepository();
  final List<Property> womanSizes = [];
  final List<Property> manSizes = [];

  final double baseWidth = 312;
  final double baseHeight = 675.2;
  double mediaWidth = 0;
  double mediaHeight = 0;
  bool isMan = true;

  //List<CustomerRepository> customerList = List<CustomerRepository>();
  bool visibleDetails = false;
  late List<GenderItem> genders;

  CustomerRepository() {
    customer = Customer();

    if (Cache().userLoggedIn != null) {
      isMan = (Cache().userLoggedIn!.sex == "m");
    }

    //_allCustomerProperties = Cache().getCustomerPropertyAll();
  }

  String? getGenderByName(String name) {
    String? dbValue;
    for (var element in genders) {
      if (element.name == name) {
        dbValue = element.dbValue;
      }
    }
    return dbValue;
  }

  String? getGenderByDBValue(String dbValue) {
    String? name;
    for (var element in genders) {
      if (element.dbValue == dbValue) {
        name = element.name;
      }
    }
    return name;
  }

  String? get name {
    return customer != null && customer!.name != null ? customer!.name : "";
  }

  String? get firstName {
    return customer != null && customer!.firstname != null ? customer!.firstname : "";
  }

  String get sex {
    if (customer == null) throw Exception("Initialize the customer object");
    return customer!.sex == "m" ? "Man" : "Woman";
  }

  int? get birthYear {
    if (customer == null) throw Exception("Initialize the customer object");
    return customer!.birthYear;
  }

  String? get goal {
    if (customer == null) throw Exception("Initialize the customer object");
    return customer!.goal;
  }

  String? getSportString() {
    if (customer == null) throw Exception("Initialize the customer object");
    String? sport;
    List<Sport>? sports = Cache().getSports();
    if (sports != null) {
      for (Sport sportObject in sports) {
        if (sportObject.sportId == customer!.sportId) {
          sport = sportObject.name;
          break;
        }
      }
    }
    return sport;
  }

  Sport? getSport() {
    if (customer == null) throw Exception("Initialize the customer object");
    Sport? sport;
    List<Sport>? sports = Cache().getSports();
    if (sports != null) {
      for (Sport sportObject in sports) {
        if (sportObject.sportId == customer!.sportId) {
          sport = sportObject;
          break;
        }
      }
    }
    return sport;
  }

  String? get fitnessLevel {
    if (customer == null) throw Exception("Initialize the customer object");
    return customer!.fitnessLevel;
  }

  String? get bodyType {
    if (customer == null) throw Exception("Initialize the customer object");
    return customer!.bodyType;
  }

  setName(String name) {
    if (customer == null) throw Exception("Initialize the customer object");
    customer!.name = name;
  }

  setFirstName(String firstName) {
    if (customer == null) throw Exception("Initialize the customer object");
    customer!.firstname = firstName;
  }

  setPassword(String password) {
    if (customer == null) throw Exception("Initialize the customer object");
    customer!.password = password;
  }

  setEmail(String email) {
    if (customer == null) throw Exception("Initialize the customer object");
    customer!.email = email;
  }

  setSex(String sex) {
    if (customer == null) throw Exception("Initialize the customer object");
    customer!.sex = sex;
  }

  setWeight(double weight) {
    const propertyName = "Weight";
    setCustomerProperty(propertyName, weight);
  }

  setHeight(int height) {
    const propertyName = "Height";
    setCustomerProperty(propertyName, height.toDouble());
  }

  setCustomerProperty(String propertyName, double value, {id = 0}) {
    if (customer == null) {
      throw Exception("Initialize the customer object");
    }
    if (customer!.properties[propertyName] == null) {
      customer!.properties[propertyName] = CustomerProperty(
          propertyId: propertyRepository.getPropertyByName("Height")!.propertyId,
          customerId: customer!.customerId == null ? 0 : customer!.customerId!,
          propertyValue: value,
          dateAdd: DateTime.now());
    } else {
      customer!.properties[propertyName]!.propertyValue = value;
    }
    customer!.properties[propertyName]!.dateAdd = DateTime.now();
    customer!.properties[propertyName]!.newData = true;
    if (id > 0) {
      customer!.properties[propertyName]!.customerPropertyId = id;
    }
    Cache().addCustomerProperty(customer!.properties[propertyName]!);
  }

  double getWeight() {
    return getCustomerPropertyValue("Weight");
  }

  double getHeight() {
    return getCustomerPropertyValue("Height");
  }

  double getCustomerPropertyValue(String propertyName) {
    if (customer == null || customer!.properties[propertyName] == null) {
      return 0.0;
    } else {
      return customer!.properties[propertyName]!.propertyValue;
    }
  }

  CustomerProperty? getCustomerProperty(String propertyName) {
    if (customer == null) throw Exception("Initialize the customer object");
    return customer!.properties[propertyName];
  }

  setBirthYear(int birthYear) {
    if (customer == null) throw Exception("Initialize the customer object");
    customer!.birthYear = birthYear;
  }

  setFitnessLevel(String level) {
    if (customer == null) throw Exception("Initialize the customer object");
    customer!.fitnessLevel = level;
  }

  setGoal(String goal) {
    if (customer == null) throw Exception("Initialize the customer object");
    customer!.goal = goal;
  }

  setSportString(String selectedSport) {
    if (customer == null) throw Exception("Initialize the customer object");
    List<Sport>? sports = Cache().getSports();
    if (sports != null) {
      for (Sport sportObject in sports) {
        if (sportObject.name == selectedSport) {
          customer!.sportId = sportObject.sportId;
          break;
        }
      }
    }
  }

  setBodyType(String bodyType) {
    if (customer == null) throw Exception("Initialize the customer object");
    customer!.bodyType = bodyType;
  }

  createNew() {
    customer = Customer();
  }

  Customer getCustomer() {
    if (customer == null) throw Exception("Initialize the customer object");
    return customer!;
  }

  void setCustomer(Customer customer) {
    customer = customer;
  }

  Future<void> addCustomer() async {
    if (customer == null) throw Exception("Initialize the customer object");
    final Customer modelCustomer = customer!;
    await CustomerApi().addCustomer(modelCustomer);
  }

  Future<void> saveCustomer() async {
    if (customer == null) throw Exception("Initialize the customer object");
    final Customer modelCustomer = customer!;
    modelCustomer.sex ??= "m";
    modelCustomer.fitnessLevel ??= "beginner";
    await CustomerApi().saveCustomer(modelCustomer);
    await saveProperties(modelCustomer.properties);
  }

  Future<void> saveProperties(LinkedHashMap<String, CustomerProperty> properties) async {
    properties.forEach((propertyName, property) async {
      if (property.newData == true) {
        await CustomerApi().addProperty(property);
        property.newData = false;
      }
    });
  }

  Future<void> savePropertyByName(String name) async {
    await Future.forEach(_properties!, (element) async {
      final CustomerProperty customerProperty = element;
      final Property? property = propertyRepository.getPropertyByName(name);
      if (property != null) {
        if (property.propertyId == customerProperty.propertyId) {
          await CustomerApi().updateProperty(customerProperty);
        }
      }
    });
  }

  Future<Customer?> getTraineeAsCustomer() async {
    _trainee = await CustomerApi().getTrainee(Cache().userLoggedIn!.customerId!);
    return _trainee;
  }

  Future<List<Customer?>?> getTrainees() async {
    int trainerId = Cache().userLoggedIn!.customerId!;
    final results = await CustomerApi().getTrainees(trainerId);
    _trainees = results;
    return results;
  }

  Future<List<CustomerProperty>> getAllCustomerProperties() async {
    int customerId = Cache().userLoggedIn!.customerId!;
    final results = await CustomerApi().getAllProperties(customerId);
    _properties = results;
    return results;
  }

  List<CustomerProperty>? getAllProperties() {
    return _properties;
  }

  List<Customer>? getTraineesList() {
    return _trainees;
  }

  void setTrainee(int traineeId) {
    if (_trainees == null) {
      return;
    }
    for (var element in _trainees!) {
      if (traineeId == element.customerId) {
        _trainee = element;
      }
    }
  }

  void emptyTrainees() {
    _trainees = null;
    _trainee = null;
  }

  Customer? getTrainee() {
    return _trainee;
  }

  Customer? getTraineeById(int customerId) {
    if (_trainees == null) {
      return null;
    }
    for (var element in _trainees!) {
      if (customerId == element.customerId) {
        _trainee = element;
      }
    }
    return _trainee;
  }

  Future<List<Purchase>> getPurchase() async {
    int customerId = Cache().userLoggedIn!.customerId!;
    List<Purchase> purchases = await PurchaseApi().getPurchasesByCustomer(customerId);
    return purchases;
  }

  Future<void> addPurchase(Purchase purchase) async {
    await PurchaseApi().savePurchase(purchase);
  }

  void setMediaDimensions(double width, double height) {
    mediaHeight = height;
    mediaWidth = width;
    addSizes(sex);
  }

  void addSizes(String sex) {
    if (customer == null) throw Exception("Initialize the customer object");
    List<Property>? properties = Cache().getProperties();
    if (properties == null) {
      return;
    }
    final double distortionWidth = mediaWidth / baseWidth;
    final double distortionHeight = mediaHeight / baseHeight;
    if (isMan) {
      for (var element in properties) {
        if (element.propertyName == "Shoulder") {
          element.top = (122 * distortionHeight).toInt();
          element.left = (130 * distortionWidth).toInt();
          element.value = customer!.getProperty("Shoulder");
          manSizes.add(element);
        } else if (element.propertyName == "Neck") {
          element.top = (68 * distortionHeight).toInt();
          element.left = (130 * distortionWidth).toInt();
          element.value = customer!.getProperty("Neck");
          manSizes.add(element);
        } else if (element.propertyName == "Biceps") {
          element.top = (178 * distortionHeight).toInt();
          element.left = (208 * distortionWidth).toInt();
          element.value = customer!.getProperty("Biceps");
          manSizes.add(element);
        } else if (element.propertyName == "Chest") {
          element.top = (154 * distortionHeight).toInt();
          element.left = (130 * distortionWidth).toInt();
          element.value = customer!.getProperty("Chest");
          manSizes.add(element);
        } else if (element.propertyName == "Belly") {
          element.top = (244 * distortionHeight).toInt();
          element.left = (130 * distortionWidth).toInt();
          element.value = customer!.getProperty("Belly");
          manSizes.add(element);
        } else if (element.propertyName == "Hip") {
          element.top = (308 * distortionHeight).toInt();
          element.left = (130 * distortionWidth).toInt();
          element.value = customer!.getProperty("Hip");
          manSizes.add(element);
        } else if (element.propertyName == "Thigh Top") {
          element.top = (332 * distortionHeight).toInt();
          element.left = (165 * distortionWidth).toInt();
          element.value = customer!.getProperty("Thigh Top");
          manSizes.add(element);
        } else if (element.propertyName == "Thigh Middle") {
          element.top = (382 * distortionHeight).toInt();
          element.left = (100 * distortionWidth).toInt();
          element.value = customer!.getProperty("Thigh Middle");
          manSizes.add(element);
        } else if (element.propertyName == "Knee") {
          element.top = (464 * distortionHeight).toInt();
          element.left = (97 * distortionWidth).toInt();
          element.value = customer!.getProperty("Knee");
          manSizes.add(element);
        } else if (element.propertyName == "Calf") {
          element.top = (520 * distortionHeight).toInt();
          element.left = (97 * distortionWidth).toInt();
          element.value = customer!.getProperty("Calf");
          manSizes.add(element);
        } else if (element.propertyName == "Ankle") {
          element.top = (620 * distortionHeight).toInt();
          element.left = (150 * distortionWidth).toInt();
          element.value = customer!.getProperty("Ankle");
          manSizes.add(element);
        } else if (element.propertyName == "Weight") {
          element.top = (402 * distortionHeight).toInt();
          element.left = (240 * distortionWidth).toInt();
          element.value = customer!.getProperty("Weight");
          manSizes.add(element);
        }
      }
    } else {
      for (var element in properties) {
        if (element.propertyName == "Shoulder") {
          element.top = (122 * distortionHeight).toInt();
          element.left = (151 * distortionWidth).toInt();
          element.value = customer!.getProperty("Shoulder");
          manSizes.add(element);
        } else if (element.propertyName == "Neck") {
          element.top = (78 * distortionHeight).toInt();
          element.left = (151 * distortionWidth).toInt();
          element.value = customer!.getProperty("Neck");
          manSizes.add(element);
        } else if (element.propertyName == "Biceps") {
          element.top = (178 * distortionHeight).toInt();
          element.left = (212 * distortionWidth).toInt();
          element.value = customer!.getProperty("Biceps");
          manSizes.add(element);
        } else if (element.propertyName == "Chest") {
          element.top = (154 * distortionHeight).toInt();
          element.left = (151 * distortionWidth).toInt();
          element.value = customer!.getProperty("Chest");
          manSizes.add(element);
        } else if (element.propertyName == "Belly") {
          element.top = (230 * distortionHeight).toInt();
          element.left = (151 * distortionWidth).toInt();
          element.value = customer!.getProperty("Belly");
          manSizes.add(element);
        } else if (element.propertyName == "Hip") {
          element.top = (294 * distortionHeight).toInt();
          element.left = (151 * distortionWidth).toInt();
          element.value = customer!.getProperty("Hip");
          manSizes.add(element);
        } else if (element.propertyName == "Thigh Top") {
          element.top = (335 * distortionHeight).toInt();
          element.left = (185 * distortionWidth).toInt();
          element.value = customer!.getProperty("Thigh Top");
          manSizes.add(element);
        } else if (element.propertyName == "Thigh Middle") {
          element.top = (377 * distortionHeight).toInt();
          element.left = (125 * distortionWidth).toInt();
          element.value = customer!.getProperty("Thigh Middle");
          manSizes.add(element);
        } else if (element.propertyName == "Knee") {
          element.top = (468 * distortionHeight).toInt();
          element.left = (129 * distortionWidth).toInt();
          element.value = customer!.getProperty("Knee");
          manSizes.add(element);
        } else if (element.propertyName == "Calf") {
          element.top = (525 * distortionHeight).toInt();
          element.left = (129 * distortionWidth).toInt();
          element.value = customer!.getProperty("Calf");
          manSizes.add(element);
        } else if (element.propertyName == "Ankle") {
          element.top = (620 * distortionHeight).toInt();
          element.left = (162 * distortionWidth).toInt();
          element.value = customer!.getProperty("Ankle");
          manSizes.add(element);
        } else if (element.propertyName == "Weight") {
          element.top = (402 * distortionHeight).toInt();
          element.left = (240 * distortionWidth).toInt();
          element.value = customer!.getProperty("Weight");
          manSizes.add(element);
        }
      }
    }
  }

  int? getWeightCoordinate(isMan, {isTop = false, isLeft = false}) {
    int? value = 0;
    for (var element in manSizes) {
      if (element.propertyName == SizesEnum.Weight.toStr()) {
        if (isTop == true) {
          value = element.top;
        } else if (isLeft == true) {
          value = element.left;
        }
      }
    }
    return value;
  }

  Property? getPropertyByName(String propertyName) {
    Property? property;
    List<Property> sizes;
    if (sex == "m") {
      sizes = manSizes;
    } else {
      sizes = womanSizes;
    }

    for (var element in sizes) {
      if (element.propertyName == propertyName) {
        property = element;
      }
    }
    return property;
  }

  void updateSizes(String propertyName, double value) {
    List<Property> sizes;
    if (sex == "m") {
      sizes = manSizes;
    } else {
      sizes = womanSizes;
    }

    for (var element in sizes) {
      if (element.propertyName == propertyName) {
        element.value = value;
      }
    }
  }

  List<CustomerProperty> getAllCustomerPropertyByName(String propertyName) {
    List<CustomerProperty> allProperties = [];

    Property? property = propertyRepository.getPropertyByName(propertyName);
    print(property);
    if (property == null || Cache().getCustomerPropertyAll() == null) {
      return allProperties;
    }

    for (var element in Cache().getCustomerPropertyAll()!) {
      if (element.propertyId == property.propertyId) {
        allProperties.add(element);
      }
    }
    return allProperties;
  }

  void initCustomerProperties() {
    List<Property>? properties = Cache().getProperties();
    Customer? customer = Cache().userLoggedIn;
    if (customer == null || customer.customerProperties.isEmpty || properties == null) {
      return;
    }

    for (var property in properties) {
      CustomerProperty? customerProperty = getCustomerPropertyById(property.propertyId);
      if (customerProperty != null) {
        customer.properties[property.propertyName] = customerProperty;
      }
    }
  }

  CustomerProperty? getCustomerPropertyById(int id) {
    CustomerProperty? property;
    Customer? customer = Cache().userLoggedIn;
    if (customer == null) {
      return property;
    }
    for (var customerProperty in customer.customerProperties) {
      if (customerProperty.propertyId == id) {
        property = customerProperty;
        break;
      }
    }
    return property;
  }
}