

import 'package:app_hit_a_wod/src/models/bi_exercises.model.dart';
import 'package:app_hit_a_wod/src/models/bi_training_session.model.dart';
import 'package:app_hit_a_wod/src/models/exercise.model.dart';
import 'package:app_hit_a_wod/src/models/training_workout.model.dart';
import 'package:app_hit_a_wod/src/providers/api.provider.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:rxdart/subjects.dart';

class StatsBloc {

  ApiProvider _api;

  List<String> categories;

  // Show Filters
  BehaviorSubject<bool> _showFiltersSubject = new BehaviorSubject();
  Stream<bool> get showFiltersStream => _showFiltersSubject.stream;
  bool get showFiltersValue => _showFiltersSubject.value;

  // Page Selected
  BehaviorSubject<int> _selectedPageStream = new BehaviorSubject();
  Stream<int> get selectedPageStream => _selectedPageStream.stream;
  int get selectedPageValue => _selectedPageStream.value;
  Function(int) get selectedPageSet => _selectedPageStream.sink.add;
  
  // Dir
  BehaviorSubject<String> _dirStream = new BehaviorSubject();
  Stream<String> get dirStream => _dirStream.stream;
  String get dirValue => _dirStream.value;
  Function(String) get dirSet => _dirStream.sink.add;

  // Training Sessions
  BehaviorSubject<List<BITrainingSession>> _trainingSessionsSubject = new BehaviorSubject();
  Stream<List<BITrainingSession>> get trainingSessionStream => _trainingSessionsSubject.stream;

  // Training Sessions Data ini
  BehaviorSubject<DateTime> _dataIniStream = new BehaviorSubject();
  Stream<DateTime> get dataIniStream => _dataIniStream.stream;
  DateTime get dataIniValue => _dataIniStream.value;
  Function(DateTime) get dataIniSet => _dataIniStream.sink.add;

  // Training Sessions Data fi
  BehaviorSubject<DateTime> _dataFiStream = new BehaviorSubject();
  Stream<DateTime> get dataFiStream => _dataFiStream.stream;
  DateTime get dataFiValue => _dataFiStream.value;
  Function(DateTime) get dataFiSet => _dataFiStream.sink.add;

  // Exercices
  BehaviorSubject<List<Exercise>> _exercisesSubject  = new BehaviorSubject();
  Stream<List<Exercise>> get exercisesStrem => _exercisesSubject.stream;
  List<Exercise> get exercisesValue => _exercisesSubject.value;

  // Exercise difficulty
  BehaviorSubject<int> _difficultyExerciseSubject = new BehaviorSubject();
  Stream<int> get difficultyExerciseStream => _difficultyExerciseSubject.stream;
  int get difficultyExerciseValue => _difficultyExerciseSubject.value;
  Function(int) get difficultyExerciseSet => _difficultyExerciseSubject.sink.add;

  // Exercise modality
  BehaviorSubject<List<String>> _modalityExerciseSubject = new BehaviorSubject();
  Stream<List<String>> get modalityExerciseStream => _modalityExerciseSubject.stream;
  List<String> get modalityExerciseValue => _modalityExerciseSubject.value;
  Function(List<String>) get modalityExerciseSet => _modalityExerciseSubject.sink.add;

  // Exercise Equipment
  BehaviorSubject<List<String>> _equipmentExerciseSubject = new BehaviorSubject();
  Stream<List<String>> get equipmentExerciseStream => _equipmentExerciseSubject.stream;
  List<String> get equipmentExerciseValue => _equipmentExerciseSubject.value;
  Function(List<String>) get equipmentExerciseSet => _equipmentExerciseSubject.sink.add;

  // Exercise exercise types
  BehaviorSubject<List<String>> _exerciseTypesExerciseSubject = new BehaviorSubject();
  Stream<List<String>> get exerciseTypesExerciseStream => _exerciseTypesExerciseSubject.stream;
  List<String> get exerciseTypesExerciseValue => _exerciseTypesExerciseSubject.value;
  Function(List<String>) get exerciseTypesExerciseSet => _exerciseTypesExerciseSubject.sink.add;

  // Workouts
  BehaviorSubject<List<TrainingWorkout>> _workoutsSubject  = new BehaviorSubject();
  Stream<List<TrainingWorkout>> get workoutsStrem => _workoutsSubject.stream;
  List<TrainingWorkout> get workoutsValue => _workoutsSubject.value;

  // Workout Equipment
  BehaviorSubject<List<String>> _equipmentWorkoutSubject = new BehaviorSubject();
  Stream<List<String>> get equipmentWorkoutStream => _equipmentWorkoutSubject.stream;
  List<String> get equipmentWorkoutValue => _equipmentWorkoutSubject.value;
  Function(List<String>) get equipmentWorkoutSet => _equipmentWorkoutSubject.sink.add;

  // Workout Sections
  List<String> allSections;
  BehaviorSubject<List<String>> _sectionsWorkoutSubject = new BehaviorSubject();
  Stream<List<String>> get sectionsWorkoutStream => _sectionsWorkoutSubject.stream;
  List<String> get sectionsWorkoutValue => _sectionsWorkoutSubject.value;
  Function(List<String>) get sectionsWorkoutSet => _sectionsWorkoutSubject.sink.add;

  // Workout seconds
  BehaviorSubject<int> _secondsWorkoutSubject = new BehaviorSubject();
  Stream<int> get secondsWorkoutStream => _secondsWorkoutSubject.stream;
  int get secondsWorkoutValue => _secondsWorkoutSubject.value;
  Function(int) get secondsWorkoutSet => _secondsWorkoutSubject.sink.add;

  // Workout difficulty
  BehaviorSubject<int> _difficultyWorkoutSubject = new BehaviorSubject();
  Stream<int> get difficultyWorkoutStream => _difficultyWorkoutSubject.stream;
  int get difficultyWorkoutValue => _difficultyWorkoutSubject.value;
  Function(int) get difficultyWorkoutSet => _difficultyWorkoutSubject.sink.add;

  // Workout favorite
  BehaviorSubject<int> _favoriteWorkoutSubject = new BehaviorSubject();
  Stream<int> get favoriteWorkoutStream => _favoriteWorkoutSubject.stream;
  int get favoriteWorkoutValue => _favoriteWorkoutSubject.value;
  Function(int) get favoriteWorkoutSet => _favoriteWorkoutSubject.sink.add;

  // Workout exercise types
  BehaviorSubject<List<String>> _exerciseTypesWorkoutSubject = new BehaviorSubject();
  Stream<List<String>> get exerciseTypesWorkoutStream => _exerciseTypesWorkoutSubject.stream;
  List<String> get exerciseTypesWorkoutValue => _exerciseTypesWorkoutSubject.value;
  Function(List<String>) get exerciseTypesWorkoutSet => _exerciseTypesWorkoutSubject.sink.add;

  // Workout category
  BehaviorSubject<String> _categoryWorkoutSubject = new BehaviorSubject();
  Stream<String> get categoryWorkoutStream => _categoryWorkoutSubject.stream;
  String get categoryWorkoutValue => _categoryWorkoutSubject.value;
  Function(String) get categoryWorkoutSet => _categoryWorkoutSubject.sink.add;

  //constructor + singleton
  static StatsBloc _instancia;

  factory StatsBloc({BuildContext context, int user_id, int box_id }) {
    if(_instancia==null) {
      _instancia = StatsBloc._internal(context, user_id, box_id);
    }
    return _instancia;
  }

  StatsBloc._internal(BuildContext context, int user_id, int box_id) {
    _api = Provider.of<ApiProvider>(context);
    this.getCategories();
    this._selectedPageStream.sink.add(0);
    this._dirStream.sink.add('desc');
    
    this.cleanFiltersWorkout();
    this.cleanFiltersExercises();

    this.getAllWorkoutSectionTypes();
    this.getWorkoutSectionTypes();
    

    this._dataIniStream.sink.add(null);
    this._dataFiStream.sink.add(null);
    this.refreshTrainingSessions(user_id, box_id);
    /* this.refreshExercises(user_id, box_id, null);
    this.refreshWorkouts(user_id,null); */
    this._showFiltersSubject.sink.add(false);
  }

  cleanFiltersWorkout() {
    // Workouts filters
    this._equipmentWorkoutSubject.sink.add(["Barbell","Barbell plate","Parallettes/Parallel bars","Bench","Racks","Dumbbell","Battle rope","Bicycle","Box jumps","Climbing rope","Dips","GHD","Gymnastic rings","Pull-up bar","Hammer","Kettlebell","Log","Medicine Ball","Rower","SandBag","Skipping rope","Sled","Stone","Swimming Pool","Tire","Vest"]);
    this._exerciseTypesWorkoutSubject.sink.add(["Abdominal","Pull-up","Static","Bike","Burpee","Jumps","Muscle-up","Cleans","Jerk","Presses","Lunges","Thruster","Climb","Curl","Deadlift","Dip","Hyperextension","Push","Jump Rope","Squat","Walking","Snatch","Push-up","Racks","Strongman","Rest","Row","Run","Swimming","Swing","Throw"]);
    this._sectionsWorkoutSubject.sink.add(null);
    this._secondsWorkoutSubject.sink.add(null);
    this._difficultyWorkoutSubject.sink.add(3);
    this._categoryWorkoutSubject.sink.add("Todos");
    this._favoriteWorkoutSubject.sink.add(0);
  }

  cleanFiltersExercises() {
    // Exercise filters
    this._equipmentExerciseSubject.sink.add(["Barbell","Barbell plate","Parallettes/Parallel bars","Bench","Racks","Dumbbell","Battle rope","Bicycle","Box jumps","Climbing rope","Dips","GHD","Gymnastic rings","Pull-up bar","Hammer","Kettlebell","Log","Medicine Ball","Rower","SandBag","Skipping rope","Sled","Stone","Swimming Pool","Tire","Vest"]);
    this._exerciseTypesExerciseSubject.sink.add(["Abdominal","Pull-up","Static","Bike","Burpee","Jumps","Muscle-up","Cleans","Jerk","Presses","Lunges","Thruster","Climb","Curl","Deadlift","Dip","Hyperextension","Push","Jump Rope","Squat","Walking","Snatch","Push-up","Racks","Strongman","Rest","Row","Run","Swimming","Swing","Throw"]);
    this._modalityExerciseSubject.sink.add(['G','M','W']);
    this._difficultyExerciseSubject.sink.add(3);
  }

  selectPage(int index, int user_id, int box_id) {
    if (index==1 && this._exercisesSubject.value==null) {
      this.refreshExercises(user_id, box_id, null);
    } else if (index==2 && this._workoutsSubject.value==null) {
      this.refreshWorkouts(user_id, null);
    }
    this._selectedPageStream.sink.add(index);
  }

  Future<bool> refreshTrainingSessions(int user_id, int box_id) async {
    this._trainingSessionsSubject.sink.add(null);
    var resp = await _api.getTrainingSessionsUserBI(user_id, box_id, this.dataIniValue, this.dataFiValue, this.dirValue);
    this._trainingSessionsSubject.sink.add(resp.data);
    return true;
  }

  Future<bool> refreshExercises(int user_id, int box_id, String name) async {
    this._exercisesSubject.sink.add(null);
    var resp = await _api.getAllExercises(user_id, box_id, DateTime.parse('1990-01-01'), DateTime.parse('2100-01-01'),name,this.dirValue, this.equipmentExerciseValue, this.difficultyExerciseValue, this.modalityExerciseValue, this.exerciseTypesExerciseValue);
    this._exercisesSubject.sink.add(resp.data);
    return true;
  }

  Future<bool> refreshWorkouts(int user_id, String name) async {
    this._workoutsSubject.sink.add(null);
    var resp = await _api.getAvailableWorkouts(user_id,name, this.dirValue, this.equipmentWorkoutValue, this.sectionsWorkoutValue, this.difficultyWorkoutValue, this.secondsWorkoutValue, (this.categoryWorkoutValue=="Todos" ? null : this.categoryWorkoutValue), this.exerciseTypesWorkoutValue, this.favoriteWorkoutValue);
    this._workoutsSubject.sink.add(resp.data);
    return true;
  }

  Future<bool> getCategories() async {
    var a = await _api.getCategories();
    this.categories = a;
    return true;
  }

  Future<bool> getWorkoutSectionTypes() async {
    List<String> t = await _api.getSectionTypes();
    this._sectionsWorkoutSubject.sink.add(t);
    return true;
  }

  Future<bool> getAllWorkoutSectionTypes() async {
    this.allSections = await _api.getSectionTypes();
    return true;
  }

  changeShowFilters(int user_id, int box_id) {
    this._showFiltersSubject.sink.add(!this.showFiltersValue);
    if (!this.showFiltersValue) {
      this.cleanFiltersWorkout();
      this.refreshWorkouts(user_id, null);
      this.cleanFiltersExercises();
      this.refreshExercises(user_id, box_id, null);
    }
  }

}

