import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges} from '@angular/core';
import {DayToDisplay, Event, EventsAvailableResponse, EventType, Trainer} from "../../services/event.service";
import * as moment from "moment";
import {FormControl, FormGroup} from "@angular/forms";
import {TimeTableFilter} from "../../app.types";

@Component({
  selector: 'app-month-calendar',
  templateUrl: './month-calendar.component.html',
  styleUrls: ['./month-calendar.component.scss']
})
export class MonthCalendarComponent implements OnInit  {

  minDate: number;
  maxDate: number;
  // daysOfWeekAll: DayOfWeek[];
  daysOfWeek: DayOfWeek[];
  trainers: Trainer[] = [];
  eventTypes: EventType[] = [];

  formTimeTable: FormGroup = new FormGroup(
    {
      "idTrainer": new FormControl("-1",),
      "idEventType": new FormControl("-1",),
    }
  )

  _eventsAvailableResponse: EventsAvailableResponse;

  _timeTableFilter: TimeTableFilter;

  @Output()
  onEvent: EventEmitter<MonthCalendarEvent> = new EventEmitter<MonthCalendarEvent>();

  @Output()
  filterChanged: EventEmitter<TimeTableFilter> = new EventEmitter<TimeTableFilter>();

  daysToDisplay: DayToDisplay[] = [];

  initialized: boolean = false;

  constructor() {
    this.formTimeTable.valueChanges.subscribe(value => {
      if ( this.initialized ){
        this.filterChanged.emit(value);
      }else{
        this.initialized = true;
      }
    })
  }

  ngOnInit() {
    this.initialized = false ;
    moment.locale('hu');
    this.formTimeTable.patchValue({
      "idTrainer": this._timeTableFilter.idTrainer,
      "idEventType": this._timeTableFilter.idEventType
    });
    this.loadData();
  }

  @Input()
  set timeTableFilter(timeTableFilter: TimeTableFilter){
    this._timeTableFilter = timeTableFilter;
    let idTrainer = timeTableFilter?.idTrainer == null ? "-1" : timeTableFilter?.idTrainer;
    let idEventType = timeTableFilter?.idEventType == null ? "-1" : timeTableFilter?.idEventType;

    this.formTimeTable.patchValue({
      "idTrainer": idTrainer,
      "idEventType": idEventType
    })
    this.loadData();
  }

  get timeTableFilter(){
    return this._timeTableFilter;
  }

  @Input()
  set eventsAvailableResponse(eventsAvailableResponse: EventsAvailableResponse){
    this._eventsAvailableResponse = eventsAvailableResponse;
    this.loadData();
  }

  get eventsAvailableResponse(){
    return this._eventsAvailableResponse;
  }

  composeDayOfWeeks() {
    this.daysOfWeek = [];
    if (this.eventsAvailableResponse) {
      for (let i = 0; i < this.eventsAvailableResponse.dates.length && i < 7; i++) {
        const date = moment.unix(this.eventsAvailableResponse.dates[i].date);
        const dayOfWeek = this.momentDateToWeekdayName(date);
        this.daysOfWeek.push(dayOfWeek);
      }
    } else {
      let startOfWeek = moment().startOf("week");
      for (let i = 0; i < 7; i++) {
        let momWeekDay = startOfWeek.clone().add(i, 'd');
        const dayOfWeek = this.momentDateToWeekdayName(momWeekDay);
        this.daysOfWeek.push(dayOfWeek);
      }
    }
  }

  private momentDateToWeekdayName(date: moment.Moment): DayOfWeek {
    return {
      name: date.format("dddd"),
      shortName: date.format("ddd"),
    };
  }

  private filterValue(filter: number, valueGetter: () => number) {
    if (filter == null || filter == -1) {
      return true;
    }
    return valueGetter() == filter;
  }

  private filterDaysOfWeek(days: DayToDisplay[]): DayToDisplay[] {
    const filteredDays: DayToDisplay[] = JSON.parse(JSON.stringify(days));

    filteredDays.forEach(day => {
      day.events = day.events.filter(value => {
        const trainerMatch = this.filterValue(this.timeTableFilter?.idTrainer, () => value.trainer.id);
        const eventTypeMatch = this.filterValue(this.timeTableFilter?.idEventType, () => value.eventType.id);
        return trainerMatch && eventTypeMatch;
      });
      day.events.sort((a: Event, b: Event) => {
        return a.start - b.start;
      })
    })

    return filteredDays;
  }


  private loadData(){
    if ( !this._eventsAvailableResponse ){
      return ;
    }
    this.composeDayOfWeeks();
    this.trainers = this.eventsAvailableResponse.trainers;
    this.eventTypes = this.eventsAvailableResponse.eventTypes;
    this.daysToDisplay = this.filterDaysOfWeek(this.eventsAvailableResponse.dates)
  }

  handleEvent($event) {
    this.onEvent.emit($event);
  }

}

export interface Day {
  date: unixTime;
  events: Event[];
  active: boolean;
}

export interface DayOfWeek {
  name: string;
  shortName: string;
}

export function dateToMoment(date: number) {
  return moment.unix(date);
}

/**
 * Unix time is the number of seconds that have elapsed since the Unix epoch,
 * that is the time 00:00:00 UTC on 1 January 1970
 */
type unixTime = number;

export interface MonthCalendarEvent {
  type: string; // type of the month calendar event
  event: Event; // the fitness event
}
