import { Component, OnInit, OnDestroy, HostListener, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { SubscriptionService } from 'src/app/services/subscription.service';
import { SubscriptionSelection } from 'src/app/models/subscription-selection.model';
import { UtilsService } from 'src/app/services/utils.service';
import { HitAWodService } from 'src/app/services/hit-a-wod.service';
import * as moment from 'moment';
import { TrainingSession } from 'src/app/models/training-session.model';
import { Subscription as Sub, Observable, Subject } from 'rxjs';
import {
  CalendarEvent,
  CalendarEventAction,
  CalendarEventTimesChangedEvent,
  CalendarView,
  DAYS_OF_WEEK,
  CalendarDateFormatter,
  CalendarWeekViewBeforeRenderEvent,
  CalendarDayViewBeforeRenderEvent,
  CalendarEventTitleFormatter,
} from 'angular-calendar';
import { CustomDateFormatter } from './custom-date-formatter.provider';
import { map } from 'rxjs/operators';
import { User } from 'src/app/models/user.model';
import { TrainingRoom } from 'src/app/models/training-room.model';
import { CustomEventTitleFormatter } from './custom-event-title-formatter.provider';
import { TrainingWorkout, TrainingType } from 'src/app/models/training-workout.model';
import { DatePipe } from '@angular/common';
import { CalendarTemplate, CalendarTemplateExclusion } from 'src/app/models/calendar-template.model';
import { NumberToWeekDayPipe } from 'src/app/pipes/number-to-week-day.pipe';

@Component({
  selector: 'app-box-calendar',
  templateUrl: './box-calendar.component.html',
  styleUrls: ['./box-calendar.component.css'],
  providers: [
    {
      provide: CalendarDateFormatter,
      useClass: CustomDateFormatter,
    },
    {
      provide: CalendarEventTitleFormatter,
      useClass: CustomEventTitleFormatter,
    }
  ]
})
export class BoxCalendarComponent implements OnInit, OnDestroy {

  //Data
  subscription_selection:SubscriptionSelection;
  training_sessions:TrainingSession[];
  coaches:User[];
  coach_selected:User;
  training_rooms:TrainingRoom[];
  training_room_selected:TrainingRoom;
  calendar_templates:CalendarTemplate[];
  training_types:TrainingType[];

  //Component subscriptions
  boxSelectorSubscription:Sub;

  //flags
  isMobile:boolean;

  //Calendar attributes
  CalendarView = CalendarView;
  view:CalendarView = CalendarView.Week;
  constDateToday:Date = new Date();
  viewDate:Date = new Date();
  start_date:Date;
  end_date:Date;
  events:CalendarEvent[];
  weekStartsOn: number = DAYS_OF_WEEK.MONDAY;
  weekendDays: number[] = [DAYS_OF_WEEK.SATURDAY, DAYS_OF_WEEK.SUNDAY];
  locale:string = 'es-ES';
  refresh: Subject<any> = new Subject();

  //detail
  detail_active:boolean = false;
  detail_ts:CalendarEvent;

  //secondary column
  active_primary:boolean = true;
  active_secondary:boolean = false;
  inactive_secondary:boolean = true;
  secondary_workouts:boolean = false;
  secondary_weeks:boolean = false;

  //workouts
  workout_search:string = "";
  workouts_by_category:{category:string, scope:string, number:number}[] = [];
  filtered_workouts:TrainingWorkout[] = [];

  //generate week
  generate_week_date_start:Date = moment(new Date()).add(1, 'week').startOf('week').toDate();
  generate_week_date_end:Date = moment(new Date()).add(1, 'week').endOf('week').toDate();
  generate_week_training_type_id:number = 1;
  secondary_weeks_main = true;
  secondary_weeks_detail = false;
  secondary_weeks_template:CalendarTemplate;

  colors: any = {
    wod: "primary",
    open: "secondary",
    olympics: "three",
    power: "four",
    endurance: "five",
    gymnastics: "six",
    unset: "seven",
    basics: "three", 
    mobility: "four",
    kids: "five",
    advance: "six",
    special: "secondary",
    megawod: "primary",
    on_ramp: "three"
  };

  constructor(private subscriptionService:SubscriptionService,
              private utilsService:UtilsService,
              private api:HitAWodService,
              private datePipe:DatePipe,
              private weekPipe:NumberToWeekDayPipe) { }

  ngOnInit(): void {
    this.boxSelectorSubscription = this.subscriptionService.currentSubscription.subscribe(
      data => {
        if(data.level !== "Box") {
          this.utilsService.showMessage("warning", "Suscripción incorrecta", "Por favor, selecciona una suscripción a nivel de box en el desplegable superior.");
        }
        else {
          this.initCalendarData(data);
        }
      }
    );
  }

  initIsMobile() {
    this.isMobile = window.matchMedia("(max-width: 992px)").matches;

    if(this.isMobile) this.view = CalendarView.Day;
    else this.view = CalendarView.Week;
  }

  @HostListener('window:resize', ['$event'])
  onResize(e) {
    this.isMobile = e.target.innerWidth < 992;

    if(this.isMobile) this.setView(CalendarView.Day);
    else this.setView(CalendarView.Week);
  }

  ngOnDestroy() {
    this.boxSelectorSubscription.unsubscribe();
  }

  selectTrainingRoom(tr:any) {
    if(tr===-1) {
      this.training_room_selected = null;
      this.secondary_weeks = false;
      this.secondary_workouts = false;
      this.active_secondary = false;
      this.inactive_secondary = true;
    }
    else this.training_room_selected = tr;
    this.fetchSessions();
  }

  next() {
    const addition = this.isMobile ? 1 : 7;
    this.viewDate = moment(this.viewDate).add(addition, 'days').toDate();
    this.setStartEndDates();
    this.fetchSessions();
  }

  previous() {
    const addition = this.isMobile ? 1 : 7;
    this.viewDate = moment(this.viewDate).subtract(addition, 'days').toDate();
    this.setStartEndDates();
    this.fetchSessions();
  }

  today() {
    this.viewDate = new Date();
    this.setStartEndDates();
    this.fetchSessions();
  }

  isSame():boolean {
    const moment1 = moment(this.viewDate);
    const moment2 = moment(this.constDateToday);
    if(this.isMobile) return moment1.isSame(moment2, 'day');
    else return moment1.isSame(moment2, 'week');
  }

  setView(view: CalendarView) {
    if(view != this.view) {
      //Hi ha un canvi de vista
      this.fetchSessions();
      this.view = view;
    }
  }

  eventClicked(evt:CalendarEvent) {
    this.detail_ts = evt;
    this.detail_active = true;
  }

  detailClosed(evt:CalendarEvent) {
    this.detail_ts = null;
    this.detail_active = false;
    if(evt) {
      //ha estat actualitzat
      this.fetchSessions();
    } 
  }

  toggleWeekGenerator() {
    if(this.isMobile) {
      if((!this.active_primary && this.secondary_workouts) || this.active_primary) {
        this.active_secondary = true;
        this.active_primary = false;
        this.secondary_weeks = true;
        this.secondary_weeks_main = true;
        this.secondary_weeks_detail = false;
        this.secondary_workouts = false;
      }
      else { //estavem 
        this.active_primary = true;
        this.active_secondary = false;
        this.secondary_weeks = false;
        this.secondary_workouts = false;
      }
    }
    else {
      if((!this.inactive_secondary && this.secondary_workouts) || this.inactive_secondary) {
        this.inactive_secondary = false;
        this.secondary_weeks = true;
        this.secondary_weeks_main = true;
        this.secondary_weeks_detail = false;
        this.secondary_workouts = false;
      }
      else {
        this.inactive_secondary = true;
        this.secondary_weeks = false;
        this.secondary_workouts = false;
      }
    }
  }

  toggleWorkoutSection() {
    if(this.isMobile) {
      if((!this.active_primary && this.secondary_weeks) || this.active_primary) {
        this.active_secondary = true;
        this.active_primary = false;
        this.secondary_weeks = false;
        this.secondary_workouts = true;
      }
      else {
        this.active_primary = true;
        this.active_secondary = false;
        this.secondary_weeks = false;
        this.secondary_workouts = false;
      }
    }
    else {
      if((!this.inactive_secondary && this.secondary_weeks) || this.inactive_secondary) {
        this.inactive_secondary = false;
        this.secondary_weeks = false;
        this.secondary_workouts = true;
      }
      else {
        this.inactive_secondary = true;
        this.secondary_weeks = false;
        this.secondary_workouts = false;
      }
    }
  }

  searchWorkouts(filters:any) {
    this.workout_search = filters.name;
    if(filters.category && filters.category==="general") filters.category = null;
    this.api.getBoxTrainingWorkouts(this.subscription_selection.box.id.toString(), filters).subscribe(
      data => {
        this.filtered_workouts = data.data;
      }
    );
  }

  getWorkoutDescription(w:TrainingWorkout):string {
    let res:string = (w.training_workout_sections.length == 1 ? w.training_workout_sections[0].type : 'Combinado');

    return res;
  }

  eventTimesChanged(event) {
    if(event.type === "drop") {
      this.workoutDropped(event);
    }
    else if(event.type === "drag") {
      this.eventDragged(event);
    }
  }

  hourSegmentClicked(start:Date) {
    if(start > this.constDateToday) {
      let ts:TrainingSession = new TrainingSession();
      ts.box_id = this.subscription_selection.box.id;
      ts.training_room_id = this.training_room_selected.id;
      ts.capacity = this.training_room_selected.capacity;
      ts.date_start = start;
      ts.date_end = moment(start).add('59', 'minute').toDate();
      ts.credits = true;
      ts.coach_id = this.coach_selected ? this.coach_selected.id : null;
  
      this.detail_ts = {
        start: start,
        end: ts.date_end,
        title: null,
        meta: { 
          ts: ts
        }
      };
  
      this.detail_active = true;
    }
  }

  getTemplateDescription(ct:CalendarTemplate):string {
    if(ct.days.indexOf(1)!=-1 && ct.days.indexOf(2)!=-1 && ct.days.indexOf(3)!=-1 && ct.days.indexOf(4)!=-1 && ct.days.indexOf(5)!=-1 && ct.days.indexOf(6)!=-1 && ct.days.indexOf(7)!=-1) {
      return "Todos los días de la semana";
    }
    else if(ct.days.indexOf(1)!=-1 && ct.days.indexOf(2)!=-1 && ct.days.indexOf(3)!=-1 && ct.days.indexOf(4)!=-1 && ct.days.indexOf(5)!=-1 && ct.days.length==5) {
      return "Todos los días laborales";
    }
    else {
      return ct.days.map(day => this.weekPipe.transform(day)).join(", ");
    }
  }

  getTemplateExclusionsDescription(ct:CalendarTemplate):string {
    if(ct.calendar_template_exclusions && ct.calendar_template_exclusions.length > 0) {
      let res = "Con paradas: ";
      res += ct.calendar_template_exclusions.map(excl => (`entre ${moment(excl.start_time_exclusion, "HH:mm:ss").format("HH:mm")} y ${moment(excl.end_time_exclusion, "HH:mm:ss").format("HH:mm")}`)).join(", ")
      return res;
    }
    else return "Sin paradas.";
  }

  generateWeek(ct:CalendarTemplate) {
    if(!this.generate_week_date_end || !this.generate_week_date_start || !this.generate_week_training_type_id) {
      this.utilsService.showMessage("info", "Faltan parámetros", "Para generar las sesiones, debes introducir las fechas y el tipo.");
    }
    else if(this.generate_week_date_start > this.generate_week_date_end) {
      this.utilsService.showMessage("info", "Fechas incorrectas", "La fecha de inicio debe ser anterior a la fecha límite.");
    }
    else if(confirm("¿Estás seguro que quieres generar las sesiones en serie?")) {
      //generate week
      this.api.postBoxGenerateCalendar(this.subscription_selection.box.id.toString(), {
        start_date: this.generate_week_date_start,
        end_date: this.generate_week_date_end,
        calendar_template_id: ct.id,
        training_room_id: this.training_room_selected.id,
        training_type_id: this.generate_week_training_type_id,
        coach_id: this.coach_selected ? this.coach_selected.id : null
      }).subscribe(
        data => {
          this.utilsService.showMessage("success", "Sesiones generadas correctamente", `Se han generado ${data.length} sesiones.`);
          this.viewDate = this.generate_week_date_start;
          this.setStartEndDates();
          this.fetchSessions();
        }
      );
    }
  }

  navigatePlantilla(ct:CalendarTemplate = null) {
    if(ct) this.secondary_weeks_template = ct;
    else {
      this.secondary_weeks_template = new CalendarTemplate();
      this.secondary_weeks_template.calendar_template_exclusions = [];
    }
    this.secondary_weeks_main = false
    this.secondary_weeks_detail = true;
  }

  navigatePlantillaMain() {
    this.secondary_weeks_detail = false;
    this.secondary_weeks_main = true;
    this.secondary_weeks_template = null;
  }

  removeException(ct:CalendarTemplate, i:number) {
    if(ct.calendar_template_exclusions && i<ct.calendar_template_exclusions.length) {
      ct.calendar_template_exclusions.splice(i, 1);
    }
  }

  addException(ct:CalendarTemplate) {
    if(!ct.calendar_template_exclusions) ct.calendar_template_exclusions = [];
    ct.calendar_template_exclusions.push(new CalendarTemplateExclusion());
  }

  savePlantilla(ct:CalendarTemplate) {
    if(ct.id) {
      this.api.putCalendarTemplate(ct).subscribe(
        data => {
          this.fetchCalendarTemplates();
          //tornem enrere
          this.navigatePlantillaMain();
        }
      )
    }
    else {
      ct.box_id = this.subscription_selection.box.id;
      this.api.postCalendarTemplate(ct).subscribe(
        data => {
          this.fetchCalendarTemplates();
          //tornem enrere
          this.navigatePlantillaMain();
        }
      );
    }
  }

  borrarPlantilla(ct:CalendarTemplate) {
    if(confirm("¿Estás seguro que quieres borrar esa plantilla?")) {
      this.api.deleteCalendarTemplate(ct.id.toString()).subscribe(
        data => {
          this.fetchCalendarTemplates();
          this.navigatePlantillaMain();
        }
      );
    }
  }

  isTemplateComplete(ct:CalendarTemplate) {
    if(!ct.days || ct.days.length==0) return false;
    if(!ct.default_duration || ct.default_duration==0) return false;
    if(!ct.start_day_time || !ct.end_day_time) return false;
    if(!ct.time_between_wods) return false;
    if(ct.calendar_template_exclusions) {
      for(let i=0; i<ct.calendar_template_exclusions.length; i++) {
        if(!ct.calendar_template_exclusions[i].start_time_exclusion) return false;
        if(!ct.calendar_template_exclusions[i].end_time_exclusion) return false;
      }
    }

    return true;
  }

  private workoutDropped(event) {
    const allDay:boolean = event.allDay;
    const workout:TrainingWorkout = event.event;
    const start:Date = event.newStart;

    if(allDay && confirm(`¿Quieres establecer el workout "${workout.name}" para los WODs del dia ${this.datePipe.transform(start, "shortDate")}?`)) {
      const body = {
        allDay: allDay,
        training_room_id: this.training_room_selected.id,
        datetime: start,
        training_workout_id: workout.id
      };
      this.api.setBulkWorkoutByBoxId(this.subscription_selection.box.id.toString(), body).subscribe(
        data => {
          this.fetchSessions();
        }
      );
    }
  }

  private eventDragged(event) {

  }

  private setStartEndDates() {
    if(this.isMobile){  
      this.start_date = moment(this.viewDate).startOf('day').toDate();
      this.end_date = moment(this.viewDate).endOf('day').toDate();
    }
    else {
      this.start_date = moment(this.viewDate).startOf('week').toDate();
      this.end_date = moment(this.viewDate).endOf('week').toDate();
    }

    this.generate_week_date_start = moment(this.start_date).startOf('week').toDate();
    this.generate_week_date_end = moment(this.start_date).endOf('week').toDate();
  }

  private initCalendarData(s:SubscriptionSelection) {
    this.subscription_selection = s;
    this.initIsMobile();
    this.setStartEndDates();
    this.fetchCoaches();
    this.fetchTrainingRooms();
    this.fetchTrainingWorkoutsTypes();
    this.fetchCalendarTemplates();
    this.fetchTrainingTypes();
  }

  private fetchCoaches() {
    this.api.getUsersThatCanBeCoaches(this.subscription_selection.box.id.toString()).subscribe(
      data => {
        this.coaches = data.data;
      }
    );
  }

  private fetchTrainingRooms() {
    this.api.getBoxTrainingRooms(this.subscription_selection.box.id.toString()).subscribe(
      data => {
        this.training_rooms = data.data;
        if(this.training_rooms.length > 0) {
          this.selectTrainingRoom(this.training_rooms[0]);
        }
        else {
          this.utilsService.showMessage("warning", "Sin salas de entrenamiento", "Tu box no tiene ninguna sala de entrenamiento creada.");
        }
      }
    );
  }

  private fetchSessions() {
    this.api.getBoxTrainingSessions( this.subscription_selection.box.id.toString(), 
                                                    this.training_room_selected?.id, this.start_date, this.end_date).pipe(
      map((tss) => {
        const res = tss.data.map((ts:TrainingSession, i:number) => {
          return {
            start: ts.date_start,
            end: ts.date_end,
            title: ts.training_type ? ts.training_type.name : 'Sin tipo',
            color: {
              primary: this.utilsService.getColor(this.colors[(ts.training_type ? ts.training_type.slug : 'unset')]),
              secondary: this.utilsService.getColor(this.colors[(ts.training_type ? ts.training_type.slug : 'unset')])
            },
            allDay: false,
            draggable: false, //this.constDateToday < ts.date_start ? true : false,
            cssClass: ts.training_type ? ts.training_type.slug : 'unset',
            meta: { ts: ts, index: i }
          }
        });
        return res;
      })
    ).subscribe(
      data => {
        this.events = data;
        this.refresh.next();
      }
    );
  }

  private fetchTrainingWorkoutsTypes() {
    this.api.getBoxTrainingWorkoutCategories(this.subscription_selection.box.id.toString()).subscribe(
      data => {
        this.workouts_by_category = data.data;
      }
    );
  }

  private fetchCalendarTemplates() {
    this.api.getBoxCalendarTemplates(this.subscription_selection.box.id.toString()).subscribe(
      data => {
        this.calendar_templates = data.data;
      }
    );
  }

  private fetchTrainingTypes() {
    this.api.getTrainingTypes().subscribe(
      data => {
        this.training_types = data.data;
      }
    );
  }

}
