import { Component, OnInit, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
import { CalendarI18NProvider, DateAdapter } from './providers';
import { CalendarNavigation } from '../../enums';
import { CalendarItem } from '../../defs';

@Component({
  selector: 'app-calendar',
  templateUrl: 'calendar.component.html',
  styleUrls: ['calendar.component.scss'],
})
export class CalendarComponent implements OnInit, OnChanges {
  @Input()
  mode: 'week' | 'month' = 'month';

  /**
   * Muss gesetzt sein wenn mode = week und month
   */
  @Input()
  year: number;
  @Output()
  yearChange = new EventEmitter<number>();

  /**
   * Muss gesetzt sein wenn mode = month
   */
  @Input()
  month: number;
  @Output()
  monthChange = new EventEmitter<number>();

  /**
   * Muss gesetzt sein wenn mode = week
   */
  @Input()
  week: number;
  @Output()
  weekChange = new EventEmitter<number>();

  @Input()
  items: CalendarItem[];

  @Input()
  minDate: Date;

  @Input()
  maxDate: Date;

  /**
   * Sollen alle Aufgaben im Indikator (Rundes Bubble) angezeigt werden
   * default: unique only
   */
  @Input()
  showAllTasks = false;

  /**
   * Sprung in Tätigkeitsliste
   */
  @Output()
  viewTasks = new EventEmitter<{ year: number; month: number; date: number }>();

  @Output()
  viewDetails = new EventEmitter<number>();

  constructor(public i18n: CalendarI18NProvider, public dateAdapter: DateAdapter) {}

  ngOnInit() {
    window['dateAdapter'] = this.dateAdapter;
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (this.mode === 'week' && changes['week'] && !!this.week && !!this.year) {
      const month = this.dateAdapter.getMonthForCalendarWeek(this.year, this.week);
      this.setMonth(month, { emit: false });
    }
  }

  private pad2 = (num: number) => {
    return (num < 10 ? '0' : '') + num;
  };

  changeMonth(val: CalendarNavigation) {
    let min: { year: number; month: number };
    let max: { year: number; month: number };

    if (this.minDate) {
      min = this.dateAdapter.getDate(this.minDate);
    }
    if (this.maxDate) {
      max = this.dateAdapter.getDate(this.maxDate);
    }

    const next = {
      year: this.year,
      month: this.month + val,
    };

    if (next.month < 1) {
      next.month = 12 + next.month;
      next.year = next.year - 1;
    } else if (next.month > 12) {
      next.month = next.month - 12;
      next.year = next.year + 1;
    }

    const nextStr = +`${next.year}${this.pad2(next.month)}`;
    const minStr = +!!min ? +`${min.year}${this.pad2(min.month)}` : undefined;
    const maxStr = +!!max ? +`${max.year}${this.pad2(max.month)}` : undefined;

    if ((!!maxStr ? nextStr <= maxStr : true) && (!!minStr ? nextStr >= minStr : true)) {
      this.setMonth(next.month);
      this.setYear(next.year);
    }
  }

  changeYear(val: CalendarNavigation) {
    let maxYear: number;
    let minYear: number;

    if (this.maxDate) {
      maxYear = this.maxDate.getFullYear();
    }

    if (this.minDate) {
      minYear = this.minDate.getFullYear();
    }

    if (
      this.year !== this.year + val &&
      (!!maxYear ? maxYear >= this.year + val : true) &&
      (!!minYear ? minYear <= this.year + val : true)
    ) {
      this.setYear(this.year + val);
    }
  }

  changeWeek(val: CalendarNavigation) {
    let min: { year: number; week: number };
    let max: { year: number; week: number };

    if (this.minDate) {
      const date = this.dateAdapter.getDate(this.minDate);
      min = {
        year: date.year,
        week: this.dateAdapter.getCalendarWeek(date.year, date.month, date.date),
      };
    }
    if (this.maxDate) {
      const date = this.dateAdapter.getDate(this.maxDate);
      max = {
        year: date.year,
        week: this.dateAdapter.getCalendarWeek(date.year, date.month, date.date),
      };
    }

    let nextWeek = this.week + val;
    let nextYear = this.year;

    if (nextWeek > 52) {
      nextWeek = 1;
      nextYear = this.year + 1;
    } else if (nextWeek === 0) {
      nextWeek = 52;
      nextYear = this.year - 1;
    }

    const nextStr = +`${nextYear}${this.pad2(nextWeek)}`;
    const minStr = !!min ? +`${min.year}${this.pad2(min.week)}` : undefined;
    const maxStr = !!max ? +`${max.year}${this.pad2(max.week)}` : undefined;

    if ((!!maxStr ? nextStr <= maxStr : true) && (!!minStr ? nextStr >= minStr : true)) {
      const nextMonth = this.dateAdapter.getMonthForCalendarWeek(nextYear, nextWeek);

      this.setWeek(nextWeek);
      this.setYear(nextYear);
      this.setMonth(nextMonth);
    }
  }

  navigateForth() {
    if (this.mode === 'month') {
      this.changeMonth(CalendarNavigation.Next);
    } else {
      this.changeWeek(CalendarNavigation.Next);
    }
  }

  navigateBack() {
    if (this.mode === 'month') {
      this.changeMonth(CalendarNavigation.Prev);
    } else {
      this.changeWeek(CalendarNavigation.Prev);
    }
  }

  setYear(year: number, options: { emit?: boolean } = { emit: true }) {
    if (this.year !== year) {
      this.year = year;

      if (options && options.emit) {
        this.yearChange.emit(year);
      }
    }
  }

  setMonth(month: number, options: { emit?: boolean } = { emit: true }) {
    if (this.month !== month) {
      this.month = month;

      if (options && options.emit) {
        this.monthChange.emit(month);
      }
    }
  }

  setWeek(week: number, options: { emit?: boolean } = { emit: true }) {
    if (this.week !== week) {
      this.week = week;

      if (options && options.emit) {
        this.weekChange.emit(week);
      }
    }
  }

  onClickDetails(target: { year: number; month: number; date?: number; week?: number }) {
    const targetDate = target;

    if (!target.date && !!target.week) {
      const dates = this.dateAdapter.getDatesForCalendarWeek(target.year, target.week);

      targetDate.date = this.dateAdapter.getDate(dates[0]).date;
      target.month = this.dateAdapter.getDate(dates[0]).month;
      targetDate.year = this.dateAdapter.getDate(dates[0]).year;
    }

    delete target.week;
    this.viewTasks.emit({
      year: target.year,
      month: target.month,
      date: target.date,
    });
  }
}
