/* tslint:disable:prefer-function-over-method */
/*
 * Copyright (C) 2021 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 {Component, Input, OnDestroy} from '@angular/core';
import {PopoverController} from '@ionic/angular';
import {SCDateSeries, SCThing, SCThingType, SCUuid} from '@openstapps/core';
import {difference, map} from 'lodash-es';
import {Subscription} from 'rxjs';
import {ScheduleProvider} from '../../../calendar/schedule.provider';
import {AddEventPopoverComponent} from '../add-event-popover.component';
import {CoordinatedSearchProvider} from '../../coordinated-search.provider';
import {
  chipSkeletonTransition,
  chipTransition,
} from '../../../../animation/skeleton-transitions/chip-loading-transition';

enum AddEventStates {
  ADDED_ALL,
  ADDED_SOME,
  REMOVED_ALL,
  UNAVAILABLE,
}

/**
 * Shows a horizontal list of action chips
 */
@Component({
  selector: 'stapps-add-event-action-chip',
  templateUrl: 'add-event-action-chip.html',
  styleUrls: ['add-event-action-chip.scss'],
  animations: [chipSkeletonTransition, chipTransition],
})
export class AddEventActionChipComponent implements OnDestroy {
  /**
   * Associated date series
   */
  associatedDateSeries: Promise<SCDateSeries[]>;

  /**
   * Disabled
   */
  disabled: boolean;

  /**
   * Icon
   */
  icon: string;

  /**
   * Label
   */
  label: string;

  /**
   * State
   */
  state: AddEventStates;

  /**
   * States
   */
  states = {
    [AddEventStates.ADDED_ALL]: {
      icon: 'events-all',
      label: 'data.chips.add_events.ADDED_ALL',
      disabled: false,
    },
    [AddEventStates.ADDED_SOME]: {
      icon: 'events-partial',
      label: 'data.chips.add_events.ADDED_SOME',
      disabled: false,
    },
    [AddEventStates.REMOVED_ALL]: {
      icon: 'events',
      label: 'data.chips.add_events.REMOVED_ALL',
      disabled: false,
    },
    [AddEventStates.UNAVAILABLE]: {
      icon: 'close',
      label: 'data.chips.add_events.UNAVAILABLE',
      disabled: true,
    },
  };

  /**
   * UUIDs
   */
  uuids: SCUuid[];

  /**
   * UUID Subscription
   */
  uuidSubscription: Subscription;

  constructor(
    readonly popoverController: PopoverController,
    readonly dataProvider: CoordinatedSearchProvider,
    readonly scheduleProvider: ScheduleProvider,
  ) {}

  /**
   * Apply state
   */
  applyState(state: AddEventStates) {
    this.state = state;
    const {label, icon, disabled} = this.states[state];
    this.label = label;
    this.icon = icon;
    this.disabled = disabled;
  }

  /**
   * TODO
   */
  ngOnDestroy() {
    this.uuidSubscription?.unsubscribe();
  }

  /**
   * Init
   */
  @Input() set item(item: SCThing) {
    // Angular optimizes and reuses components, so in lists, sometimes the same
    // component is used for different items. This means that the component
    // suddenly changes to a different item. This is a problem because the
    // component is not aware of the new item if we just used ngOnInit.
    if (this.uuidSubscription) {
      this.uuidSubscription.unsubscribe();
    }

    this.associatedDateSeries =
      item.type === SCThingType.DateSeries
        ? Promise.resolve([item as SCDateSeries])
        : this.dataProvider
            .coordinatedSearch({
              filter: {
                arguments: {
                  filters: [
                    {
                      arguments: {
                        field: 'type',
                        value: SCThingType.DateSeries,
                      },
                      type: 'value',
                    },
                    {
                      arguments: {
                        field: 'event.uid',
                        value: item.uid,
                      },
                      type: 'value',
                    },
                  ],
                  operation: 'and',
                },
                type: 'boolean',
              },
            })
            .then(it => it.data as SCDateSeries[]);

    this.uuidSubscription = this.scheduleProvider.uuids$.subscribe(
      async result => {
        this.uuids = result;
        const associatedDateSeries = await this.associatedDateSeries;
        if (associatedDateSeries.length === 0) {
          this.applyState(AddEventStates.UNAVAILABLE);

          return;
        }
        switch (
          difference(map(associatedDateSeries, 'uid'), this.uuids).length
        ) {
          case 0:
            this.applyState(AddEventStates.ADDED_ALL);
            break;
          case associatedDateSeries.length:
            this.applyState(AddEventStates.REMOVED_ALL);
            break;
          default:
            this.applyState(AddEventStates.ADDED_SOME);
            break;
        }
      },
    );
  }

  /**
   * Action
   */
  async onClick(event: MouseEvent) {
    const associatedDateSeries = await this.associatedDateSeries;
    const popover = await this.popoverController.create({
      component: AddEventPopoverComponent,
      translucent: true,
      cssClass: 'add-event-popover',
      componentProps: {
        items: associatedDateSeries,
      },
      event: event,
    });
    await popover.present();
  }
}
