/*
 * 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 {Component, DestroyRef, inject, Input, ViewChild} from '@angular/core';
import {IonRouterOutlet, ModalController} from '@ionic/angular/standalone';
import {SCDateSeries, SCThing, SCThingType, SCUuid} from '@openstapps/core';
import {Subscription} from 'rxjs';
import {ScheduleProvider} from '../../../calendar/schedule.provider';
import {CoordinatedSearchProvider} from '../../coordinated-search.provider';
import {
  chipSkeletonTransition,
  chipTransition,
} from '../../../../animation/skeleton-transitions/chip-loading-transition';
import {AddEventStates, AddEventStatesMap} from './add-event-action-chip.config';
import {EditEventSelectionComponent} from '../edit-event-selection.component';
import {AddEventReviewModalComponent} from '../../../calendar/add-event-review-modal.component';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {MaterialSymbol} from 'material-symbols';

/**
 * 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 {
  /**
   * Associated date series
   */
  associatedDateSeries: Promise<SCDateSeries[]>;

  /**
   * Color
   */
  color: string;

  /**
   * Disabled
   */
  disabled: boolean;

  /**
   * Icon
   */
  icon: MaterialSymbol;

  /**
   * Current state of icon fill
   */
  iconFill: boolean;

  /**
   * Label
   */
  label: string;

  /**
   * State
   */
  state: AddEventStates;

  /**
   * States
   */
  states = AddEventStatesMap;

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

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

  @ViewChild('selection', {static: false})
  selection: EditEventSelectionComponent;

  destroy$ = inject(DestroyRef);

  constructor(
    readonly dataProvider: CoordinatedSearchProvider,
    readonly modalController: ModalController,
    readonly scheduleProvider: ScheduleProvider,
    readonly routerOutlet: IonRouterOutlet,
  ) {}

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

  async export() {
    const modal = await this.modalController.create({
      component: AddEventReviewModalComponent,
      canDismiss: true,
      cssClass: 'add-modal',
      componentProps: {
        dismissAction: () => {
          modal.dismiss();
        },
        dateSeries: this.selection.selection.children
          .flatMap(it => it.children)
          .filter(it => it.selected)
          .map(it => it.item),
      },
      mode: 'md', // TODO Remove if Issue 239 is solved.
    });

    await modal.present();
    await modal.onWillDismiss();
  }

  /**
   * 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$
      .pipe(takeUntilDestroyed(this.destroy$))
      .subscribe(async result => {
        this.uuids = result;
        const associatedDateSeries = await this.associatedDateSeries;
        if (associatedDateSeries.length === 0) {
          this.applyState(AddEventStates.UNAVAILABLE);

          return;
        }
        switch (associatedDateSeries.map(it => it.uid).filter(it => !this.uuids.includes(it)).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;
          }
        }
      });
  }
}
