import 'dart:async';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/property.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/fitness_state.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'package:meta/meta.dart';

part 'exercise_new_event.dart';
part 'exercise_new_state.dart';

class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> {
  final ExerciseRepository exerciseRepository;
  final CustomerRepository customerRepository;
  final MenuBloc menuBloc;
  AnimationController bmiAnimationController;
  double quantity = 12;
  double unitQuantity = 30;
  double bmi = 0;
  double bmr = 0;
  double goalBMI = 0;
  double goalWeight = 0;
  double bmiAngle = 0;
  double bmiTop = 0;
  double bmiLeft = 0;
  double weight;
  double height;
  String fitnessLevel;
  bool changedWeight = false;
  bool changedSizes = false;
  final List<Property> womanSizes = List();
  final List<Property> manSizes = List();

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

  @override
  ExerciseNewBloc({this.exerciseRepository, this.menuBloc, this.customerRepository, ExerciseType exerciseType})
      : super(ExerciseNewInitial()) {
    exerciseRepository.setUnit(exerciseType.unit);
    exerciseRepository.setQuantity(quantity);
    exerciseRepository.setUnitQuantity(unitQuantity);
    if (Cache().userLoggedIn != null) {
      customerRepository.customer = Cache().userLoggedIn;
      weight = customerRepository.customer.getProperty("Weight");
      height = customerRepository.customer.getProperty("Height");
      fitnessLevel = customerRepository.customer.fitnessLevel;
      this.isMan = (customerRepository.customer.sex == "m");
      print("Sex Man? " + isMan.toString() + " " + customerRepository.customer.sex);
    }
  }

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

  void addSizes(String sex) {
    List<Property> properties = Cache().getProperties();
    if (properties == null) {
      return;
    }
    final double distortionWidth = mediaWidth / baseWidth;
    final double distortionHeight = mediaHeight / baseHeight;
    print("distiortionW " + distortionWidth.toString() + " dH " + distortionHeight.toString());
    if (isMan) {
      properties.forEach((element) {
        if (element.propertyName == "Shoulder") {
          element.top = (122 * distortionHeight).toInt();
          element.left = (130 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Shoulder");
          manSizes.add(element);
        } else if (element.propertyName == "Neck") {
          element.top = (68 * distortionHeight).toInt();
          element.left = (130 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Neck");
          manSizes.add(element);
        } else if (element.propertyName == "Biceps") {
          element.top = (178 * distortionHeight).toInt();
          element.left = (208 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Biceps");
          manSizes.add(element);
        } else if (element.propertyName == "Chest") {
          element.top = (154 * distortionHeight).toInt();
          element.left = (130 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Chest");
          manSizes.add(element);
        } else if (element.propertyName == "Belly") {
          element.top = (244 * distortionHeight).toInt();
          element.left = (130 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Belly");
          manSizes.add(element);
        } else if (element.propertyName == "Hip") {
          element.top = (308 * distortionHeight).toInt();
          element.left = (130 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Hip");
          manSizes.add(element);
        } else if (element.propertyName == "Thigh Top") {
          element.top = (332 * distortionHeight).toInt();
          element.left = (165 * distortionWidth).toInt();
          element.value = customerRepository.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 = customerRepository.customer.getProperty("Thigh Middle");
          manSizes.add(element);
        } else if (element.propertyName == "Knee") {
          element.top = (464 * distortionHeight).toInt();
          element.left = (97 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Knee");
          manSizes.add(element);
        } else if (element.propertyName == "Calf") {
          element.top = (520 * distortionHeight).toInt();
          element.left = (97 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Calf");
          manSizes.add(element);
        } else if (element.propertyName == "Ankle") {
          element.top = (620 * distortionHeight).toInt();
          element.left = (150 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Ankle");
          manSizes.add(element);
        } else if (element.propertyName == "Weight") {
          element.top = (402 * distortionHeight).toInt();
          element.left = (240 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Weight");
          manSizes.add(element);
        }
      });
    } else {
      properties.forEach((element) {
        if (element.propertyName == "Shoulder") {
          element.top = (122 * distortionHeight).toInt();
          element.left = (151 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Shoulder");
          print("CHEST top: " + element.top.toString() + " left " + element.left.toString());
          manSizes.add(element);
        } else if (element.propertyName == "Neck") {
          element.top = (78 * distortionHeight).toInt();
          element.left = (151 * distortionWidth).toInt();
          print("Neck top: " + element.top.toString() + " left " + element.left.toString());
          element.value = customerRepository.customer.getProperty("Neck");
          manSizes.add(element);
        } else if (element.propertyName == "Biceps") {
          element.top = (178 * distortionHeight).toInt();
          element.left = (212 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Biceps");
          manSizes.add(element);
        } else if (element.propertyName == "Chest") {
          element.top = (154 * distortionHeight).toInt();
          element.left = (151 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Chest");
          manSizes.add(element);
        } else if (element.propertyName == "Belly") {
          element.top = (230 * distortionHeight).toInt();
          element.left = (151 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Belly");
          manSizes.add(element);
        } else if (element.propertyName == "Hip") {
          element.top = (294 * distortionHeight).toInt();
          element.left = (151 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Hip");
          manSizes.add(element);
        } else if (element.propertyName == "Thigh Top") {
          element.top = (335 * distortionHeight).toInt();
          element.left = (185 * distortionWidth).toInt();
          element.value = customerRepository.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 = customerRepository.customer.getProperty("Thigh Middle");
          manSizes.add(element);
        } else if (element.propertyName == "Knee") {
          element.top = (468 * distortionHeight).toInt();
          element.left = (129 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Knee");
          manSizes.add(element);
        } else if (element.propertyName == "Calf") {
          element.top = (525 * distortionHeight).toInt();
          element.left = (129 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Calf");
          manSizes.add(element);
        } else if (element.propertyName == "Ankle") {
          element.top = (620 * distortionHeight).toInt();
          element.left = (162 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Ankle");
          manSizes.add(element);
        } else if (element.propertyName == "Weight") {
          element.top = (402 * distortionHeight).toInt();
          element.left = (240 * distortionWidth).toInt();
          element.value = customerRepository.customer.getProperty("Weight");
          manSizes.add(element);
        }
      });
    }
  }

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

    sizes.forEach((element) {
      if (element.propertyName == propertyName) {
        element.value = value;
      }
    });
  }

  @override
  Stream<ExerciseNewState> mapEventToState(ExerciseNewEvent event) async* {
    try {
      if (event is ExerciseNewLoad) {
        yield ExerciseNewLoading();
        yield ExerciseNewReady();
      } else if (event is ExerciseNewQuantityChange) {
        yield ExerciseNewLoading();
        exerciseRepository.setQuantity(event.quantity);
        quantity = event.quantity;
        yield ExerciseNewReady();
      } else if (event is ExerciseNewQuantityUnitChange) {
        yield ExerciseNewLoading();
        exerciseRepository.setUnitQuantity(event.quantity);
        unitQuantity = event.quantity;
        yield ExerciseNewReady();
      } else if (event is ExerciseNewWeightChange) {
        yield ExerciseNewLoading();
        customerRepository.setWeight(event.value.toInt());
        changedWeight = true;
        weight = event.value;
        getBMI();
        getBMR();
        yield ExerciseNewReady();
      } else if (event is ExerciseNewFitnessLevelChange) {
        yield ExerciseNewLoading();
        customerRepository.setFitnessLevel(event.value);
        fitnessLevel = event.value;
        changedWeight = true;
        getBMR();
        yield ExerciseNewReady();
      } else if (event is ExerciseNewHeightChange) {
        yield ExerciseNewLoading();
        customerRepository.setHeight(event.value.toInt());
        changedWeight = true;
        height = event.value;
        getBMI();
        getBMR();
        yield ExerciseNewReady();
      } else if (event is ExerciseNewSaveWeight) {
        yield ExerciseNewLoading();
        customerRepository.saveCustomer();
        changedWeight = false;
        this.changedSizes = false;
        yield ExerciseNewReady();
      } else if (event is ExerciseNewSizeChange) {
        yield ExerciseNewLoading();
        this.changedSizes = true;
        this.updateSizes(event.propertyName, event.value);
        customerRepository.setCustomerProperty(event.propertyName, event.value);
        yield ExerciseNewReady();
      } else if (event is ExerciseNewSubmit) {
        yield ExerciseNewLoading();
        await exerciseRepository.addExercise();
        menuBloc.add(MenuTreeDown(parent: 0));
        yield ExerciseNewReady();
      } else if (event is ExerciseNewBMIAnimate) {
        yield ExerciseNewLoading();
        yield ExerciseNewReady();
      }
    } on Exception catch (e) {
      yield ExerciseNewError(message: e.toString());
    }
  }

  double getBMI() {
    if (height == 0) {
      this.bmi = 0;
      return 0;
    }
    this.bmi = weight / (height * height / 10000);
    this.getGoalBMI();
    return this.bmi;
  }

  double getBMR() {
    var date = DateTime.now();

    int year = int.parse(DateFormat(DateFormat.YEAR).format(date));

    if (customerRepository.customer.sex == "m") {
      //66.47 + ( 13.75 × tömeg kg-ban ) + ( 5.003 × magasság cm-ben ) − ( 6.755 × életkor évben kifejezve )
      bmr = 66.47 + (13.75 * weight) + (5.003 * height) - (6.755 * (year - customerRepository.customer.birthYear));
    } else {
      //BMR = 655.1 + ( 9.563 × ömeg kg-ban ) + ( 1.85 × magasság cm-ben) − ( 4.676 × életkor évben kifejezve )
      bmr = 655.1 + (9.563 * weight) + (1.85 * height) - (4.676 * (year - customerRepository.customer.birthYear));
    }

    if (customerRepository.customer.fitnessLevel == FitnessState.beginner) {
      bmr *= 1.2;
    } else if (customerRepository.customer.fitnessLevel == FitnessState.intermediate) {
      bmr *= 1.375;
    } else if (customerRepository.customer.fitnessLevel == FitnessState.advanced) {
      bmr *= 1.55;
    } else if (customerRepository.customer.fitnessLevel == FitnessState.professional) {
      bmr *= 1.9;
    }
    return bmr;
  }

  double getGoalBMI() {
    if (this.bmi == 0) {
      getBMI();
    }
    //bmi = 15;
    this.bmiAngle = (bmi * 90 / 25) - 90;
    if (bmi < 18.5) {
      goalBMI = 19;
      this.bmiTop = 99;
      this.bmiLeft = 72;
      bmiAngle = -62;
    } else if (bmi < 25 && 18.5 < bmi) {
      goalBMI = bmi;
      this.bmiTop = 46;
      this.bmiLeft = 130;
      bmiAngle = -21;
    } else if (bmi < 30 && 24.9 < bmi) {
      goalBMI = 24;
      this.bmiTop = 38.0;
      this.bmiLeft = 186.0;
    } else if (bmi < 34.9 && 29.9 < bmi) {
      goalBMI = 29;
      bmiTop = 48;
      bmiLeft = 211;
    } else if (bmi > 35) {
      goalBMI = 34;
      bmiTop = 94;
      bmiLeft = 260;
      bmiAngle = 59;
    }

    this.goalWeight = goalBMI * (height * height / 10000);

    //print("Angle: " + bmiAngle.toStringAsFixed(1));

    return goalBMI;
  }
}