import {Component, OnInit} from '@angular/core';
import {Event, EventService, EventType} from "../../services/event.service";
import {FormBuilder, FormGroup, Validators} from "@angular/forms";
import {of, pipe, EMPTY} from "rxjs";
import {flatMap, mergeMap} from "rxjs/operators";
@Component({
  selector: 'app-events',
  templateUrl: './events.component.html',
  styleUrls: ['./events.component.scss']
})
export class EventsComponent implements OnInit {

  types: EventType[];
  eventTypeForm: FormGroup;

  originalEvents: Event[] = [];
  events: Event[] = [];

  eventDays: EventDate[] = [];

  selectedEventType: number = null;

  event: Event;

  constructor(private eventService: EventService,
              private formBuilder: FormBuilder,) {

    this.eventTypeForm = this.formBuilder.group({
      eventType: ['', [Validators.required]],
    });

    this.eventTypeForm.get('eventType').valueChanges.subscribe((params) => {
      this.selectedEventType = params;
      this.filterEvents();
    });

  }

  filterEvents() {
    this.eventTypeForm.get('eventType');
    this.events = this.originalEvents;
    if (this.selectedEventType && this.selectedEventType > 0) {
      this.events = this.originalEvents.filter(
        value => value.eventType.id == this.selectedEventType
      );
    }
    this.prepareEventDates(this.events);
  }


  ngOnInit() {
    this.event = null;
    of(null).pipe(
      flatMap(() => this.eventService.findAllEventTypes()),
      flatMap(value => {
        this.types = value;
        return of(null)
      }),
      flatMap(() => this.eventService.findEvents()),
      flatMap(value => {
        this.originalEvents = value;
        return of(null)
      }),
      flatMap(() => {
        this.filterEvents();
        return of(null)
      })
    ).subscribe();
  }

  mayRegister(event: Event) {
    return event.hasFreeSeats && event.registrations.length == 0;
  }

  // mayCancel(event: Event) {
  //   return event.reservedAt;
  // }

  noFreeSeat(event: Event) {
    return !event.hasFreeSeats;
  }

  prepareEventDates(events: Event[]) {
    this.eventDays = [];
    let date = new Date();
    date.setSeconds(0);
    date.setMilliseconds(0);

    // we will display events for the next 28 days
    for (let dayIndex = 0; dayIndex < 14; dayIndex++) {
      // the day with the current time
      let day = new Date(date.getTime() + (dayIndex * 1000 * 60 * 60 * 24));
      let dayAt = day;
      // the day with start of day
      let dayStartAt = new Date(dayAt.getTime());
      dayStartAt.setHours(0, 0, 0, 0);
      let eventDate = {
        date: day.getTime(),
        hours: []
      };
      let hourIndex = 0;
      let iterate = true;

      // on the current date we will display events from this timestamp.
      // We need this, because we display on the first day from the current timestampe
      // but on the other days, from the start of the day
      let startDisplayAt = dayIndex == 0 ? dayAt.getTime() : dayStartAt.getTime();
      // for each day add all hours in the present and future
      while (iterate) {

        let hour = new Date(startDisplayAt + (hourIndex * (1000 * 60 * 60)));
        hour.setHours(hour.getHours(), 0, 0, 0);
        // we have increased the hour of the day
        // if there was no dayswitch because of the hour increase, we can add this hour slot to the current hour
        iterate = hour.getMonth() == dayAt.getMonth() && hour.getDate() == dayAt.getDate();
        hourIndex = hourIndex + 1;
        // add the hour
        if (iterate) {
          let eventHour = {
            hour: hour.getTime(),
            events: []
          };
          // iterate over all events, and put each event to it's hour slot
          for (let j = 0; j < events.length; j++) {
            let currentEvent = events[j];
            let hourStart = hour;
            let hourEnd = new Date(hour.getTime() + (1000 * 60 * 60));
            // if event is in this day
            if (currentEvent.start >= hourStart.getTime() && currentEvent.start < hourEnd.getTime()) {
              eventHour.events.push(currentEvent);
            }
          }
          if (eventHour.events.length) {
            eventDate.hours.push(eventHour);
          }
        }
      }
      if (eventDate.hours.length) {
        this.eventDays.push(eventDate);
      }

    }
  }

  open(event: Event) {
    of(null).pipe(
      mergeMap(() => this.eventService.findEvent(event.id) ),
      mergeMap(event => {this.event = event; return of(null)} )
    ).subscribe();
  }

  closeEvent(event: Event) {
    this.event = null;
  }

  cancel(event: Event) {

  }

  register(event: Event) {

  }
}


export interface EventDate {
  date: number;
  hours: EventHour[];
}

export interface EventHour {
  hour: number;
  events: Event[];

}
