/*
 * 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, HostListener, Input, OnInit, ViewChild} from '@angular/core';
import {Location} from '@angular/common';
import {ActivatedRoute, Router} from '@angular/router';
import {AnimationController, IonRouterOutlet} from '@ionic/angular/standalone';
import {SharedAxisChoreographer} from '../../../animation/animation-choreographer';
import {materialSharedAxisX} from '../../../animation/material-motion';
import {ScheduleResponsiveBreakpoint} from './schema/schema';
import {CalendarService} from '../../calendar/calendar.service';
import moment from 'moment';
import {fabExpand} from '../../../animation/fab-expand';

/**
 * This needs to be sorted by break point low -> high
 *
 * Last entry must have `until: Infinity`
 */
const responsiveConfig: ScheduleResponsiveBreakpoint[] = [
  {
    until: 768,
    days: 3,
    startOf: 'day',
  },
  {
    until: 1700,
    days: 3,
    startOf: 'day',
  },
  {
    until: Number.POSITIVE_INFINITY,
    days: 7,
    startOf: 'week',
  },
];

/**
 * Component that displays the schedule
 */
@Component({
  selector: 'stapps-schedule-page',
  templateUrl: 'schedule-page.html',
  styleUrls: ['schedule-page.scss'],
  animations: [materialSharedAxisX],
})
export class SchedulePageComponent implements OnInit, AfterViewInit {
  /**
   * Current width of the window
   */
  private currentWindowWidth: number = window.innerWidth;

  /**
   * Actual Segment Tab
   */
  actualSegmentValue?: string | null;

  /**
   * Trigger event to go to today in calendar component
   */

  /**
   * Layout
   */
  layout: ScheduleResponsiveBreakpoint = SchedulePageComponent.getDaysToDisplay(this.currentWindowWidth);

  @ViewChild('segment') segmentView!: HTMLIonSegmentElement;

  /**
   * Show the navigation drawer
   */
  @Input() showDrawer = true;

  /**
   * Search value from search bar
   */
  queryText: string;

  /**
   * Choreographer for the tab switching
   */
  tabChoreographer: SharedAxisChoreographer<string | null | undefined>;

  isModalOpen = false;

  fabAnimation = fabExpand(this.animationController);

  /**
   * Amount of days that should be shown according to current display width
   */
  static getDaysToDisplay(width: number): ScheduleResponsiveBreakpoint {
    // the search could be optimized, but probably would have little
    // actual effect with five entries.
    // we can be sure we get a hit when the last value.until is infinity
    // (unless someone has a display that reaches across the universe)
    return responsiveConfig.find(value => width < value.until) ?? responsiveConfig.at(-1)!;
  }

  constructor(
    private readonly activatedRoute: ActivatedRoute,
    private calendarService: CalendarService,
    readonly routerOutlet: IonRouterOutlet,
    private router: Router,
    private animationController: AnimationController,
    private location: Location,
  ) {}

  ngOnInit() {
    this.onInit();
  }

  /**
   * ngOnInit is not reliably called after first navigation to app/schedule. This leads to URL and segmentView being out of sync.
   * ionViewWillEnter is called on second, third, ... navigation to app/schedule
   */
  ionViewWillEnter() {
    this.onInit();
    this.segmentView.value = this.tabChoreographer.currentValue ?? undefined;
  }

  ngAfterViewInit() {
    this.segmentView.value = this.tabChoreographer.currentValue ?? undefined;
  }

  onInit() {
    this.tabChoreographer = new SharedAxisChoreographer(this.activatedRoute.snapshot.paramMap.get('mode'), [
      'calendar',
      'weekly-view',
      'single',
    ]);
  }

  /**
   * Resize callback
   *
   * Note: this may not fire when the browser transfers from full screen to windowed
   * (Firefox & Chrome tested)
   */
  @HostListener('window:resize', ['$event'])
  onResize(_: UIEvent) {
    const current = SchedulePageComponent.getDaysToDisplay(this.currentWindowWidth);
    const next = SchedulePageComponent.getDaysToDisplay(window.innerWidth);
    this.currentWindowWidth = window.innerWidth;

    if (current.days === next.days) {
      this.layout = next;
    }
  }

  /**
   * When the segment changes
   */
  onSegmentChange() {
    const url = this.router.createUrlTree(['schedule', this.segmentView.value]).toString();
    this.location.go(url);
    this.tabChoreographer.changeViewForState(this.segmentView.value as string | undefined);
  }

  onTodayClick() {
    this.calendarService.emitGoToDate(moment().startOf('day'));
  }
}
