/*
 * Copyright (C) 2023 StApps
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */
import {AfterViewInit, Component, Input, OnInit, ViewChild} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import moment, {Moment} from 'moment';
import {materialFade, materialManualFade, materialSharedAxisX} from '../../../animation/material-motion';
import {ScheduleProvider} from '../../calendar/schedule.provider';
import {SCISO8601Date, SCUuid} from '@openstapps/core';
import {ScheduleEvent, ScheduleResponsiveBreakpoint} from './schema/schema';
import {CalendarService} from '../../calendar/calendar.service';
import {CalendarComponent} from './components/calendar.component';
import {IonContent, IonDatetime} from '@ionic/angular/standalone';
import {SwiperComponent} from 'swiper/angular';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';

/**
 * Component that displays the schedule
 */
@Component({
  selector: 'stapps-schedule-view',
  templateUrl: 'schedule-view.html',
  styleUrls: ['schedule-view.scss', './components/calendar-component.scss'],
  animations: [materialFade, materialSharedAxisX, materialManualFade],
})
export class ScheduleViewComponent extends CalendarComponent implements OnInit, AfterViewInit {
  @ViewChild('mainSwiper') mainSwiper: SwiperComponent;

  @ViewChild('headerSwiper') headerSwiper: SwiperComponent;

  @ViewChild('content') content: IonContent;

  /**
   * The day that the schedule started out on
   */
  baselineDate: Moment;

  /**
   * Hours for grid
   */
  readonly hours: number[];

  /**
   * Range of hours to display
   */
  @Input() readonly hoursRange = {
    from: 5,
    to: 22,
  };

  /**
   * Layout of the schedule
   */
  @Input() layout: ScheduleResponsiveBreakpoint;

  schedule: Record<SCISO8601Date, Record<SCUuid, ScheduleEvent>> = {};

  /**
   * unix -> (uid -> event)
   */
  @Input() testSchedule: Record<SCISO8601Date, Record<SCUuid, ScheduleEvent>> = {};

  /**
   * Route Fragment
   */
  // @Override
  routeFragment = 'schedule/recurring';

  // start at fist weekday depending on locale
  weekDates = Array.from({length: 7}).map(
    // eslint-disable-next-line unicorn/consistent-function-scoping
    (_, i) => moment().startOf('week').add(i, 'days'),
  );

  constructor(
    activatedRoute: ActivatedRoute,
    calendarService: CalendarService,
    scheduleProvider: ScheduleProvider,
  ) {
    super(activatedRoute, calendarService, scheduleProvider);
    const hoursAmount = this.hoursRange.to - this.hoursRange.from + 1;
    this.hours = [...Array.from({length: hoursAmount}).keys()];
  }

  /**
   * Initialize
   */
  ngOnInit() {
    super.ngOnInit();
    this.calendarService.goToDateClicked.pipe(takeUntilDestroyed(this.destroy$)).subscribe(() => {
      this.slideToToday();
    });
  }

  ngAfterViewInit() {
    this.slideToToday();
  }

  /**
   * Slide today into view.
   */
  slideToToday() {
    const todayIndex = Number(moment().startOf('week').format('d')) + 1;
    this.mainSwiper?.swiperRef.slideTo(todayIndex);
    this.setDateRange(todayIndex);

    this.scrollCursorIntoView(this.content);
  }

  /**
   * Load events
   */
  // @Override
  async loadEvents(): Promise<number> {
    const dateSeries = await this.scheduleProvider.getDateSeries(
      this.uuids,
      ['P1W', 'P2W', 'P3W', 'P4W'],
      moment(moment.now()).startOf('week').toISOString(),
    );

    this.testSchedule = {};

    for (const series of dateSeries.dates) {
      const weekDays = Object.keys(
        series.dates.reduce(
          (accumulator, date) => {
            accumulator[moment(date).weekday()] = true;
            return accumulator;
          },
          {} as Record<number, true>,
        ),
      );

      for (const day of weekDays) {
        // fall back to default
        (this.testSchedule[day] ?? (this.testSchedule[day] = {}))[series.uid] = {
          dateSeries: series,
          time: {
            start: moment(series.dates[0]).hours(),
            duration: series.duration,
          },
        };
      }
    }

    return this.todaySlideIndex;
  }

  presentScheduleDatePopover(index: number, popoverDateTime: IonDatetime) {
    const nextIndex =
      moment(popoverDateTime.value).diff(this.baselineDate, 'days') -
      this.headerSwiper.swiperRef.realIndex -
      index;

    this.mainSwiper.swiperRef.slideTo(nextIndex);
    this.setDateRange(nextIndex);
    popoverDateTime.confirm(true);
  }
}
