import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { ControlContainer, FormGroup } from '@angular/forms';
import { ComponentStore } from '@ngrx/component-store';
import { CommunicationDetailsDTO } from '@swagger/checkout';
import { NotificationChannel } from '@swagger/oms';
import { NEVER, Observable } from 'rxjs';
import { map, shareReplay, startWith, tap } from 'rxjs/operators';

export interface SharedNotificationChannelControlComponentState {
  open: boolean;
}

@Component({
  selector: 'shared-notification-channel-control',
  templateUrl: './notification-channel-control.component.html',
  styleUrls: ['./notification-channel-control.component.scss'],
})
export class SharedNotificationChannelControlComponent extends ComponentStore<SharedNotificationChannelControlComponentState>
  implements OnInit {
  notificationGroup: FormGroup;

  @Input()
  communicationDetails?: CommunicationDetailsDTO;

  @Input()
  channelActionName?: string; // z.B. Erneut senden

  @Input()
  channelActionLoading?: boolean;

  @Output()
  channelActionEvent = new EventEmitter<NotificationChannel[]>();

  get notificationChannelControl() {
    return this.notificationGroup.get('selected');
  }

  get emailControl() {
    return this.notificationGroup.get('email');
  }

  get displayEmail() {
    return !!(this.notificationChannelControl.value & 1) && this.emailControl;
  }

  get mobileControl() {
    return this.notificationGroup.get('mobile');
  }

  get displayMobile() {
    return !!(this.notificationChannelControl.value & 2) && this.mobileControl;
  }

  get displayToggle() {
    return this.displayEmail || this.displayMobile;
  }

  get hasError() {
    return !!(this.mobileControl?.errors || this.emailControl?.errors);
  }

  readonly open$ = this.select((s) => s.open).pipe(shareReplay());

  readonly options: NotificationChannel[] = [1, 2];

  get notificationChannels() {
    const value = this.notificationChannelControl?.value;

    let values: NotificationChannel[] = [];

    this.options?.forEach((option) => {
      if (value & option) {
        values.push(option);
      }
    });
    return values;
  }

  notificationChannels$: Observable<NotificationChannel[]>;

  constructor(private _notificationsGroup: ControlContainer, private _cdr: ChangeDetectorRef) {
    super({
      open: false,
    });
  }

  ngOnInit(): void {
    if (this._notificationsGroup.control instanceof FormGroup) {
      this.notificationGroup = this._notificationsGroup.control;
    }
    this.initNotificationChannels$();
  }

  initNotificationChannels$() {
    if (this.notificationGroup) {
      this.notificationChannels$ = this.notificationChannelControl.valueChanges.pipe(startWith(this.notificationChannelControl.value)).pipe(
        map((value) => {
          let values = [];

          this.options?.forEach((option) => {
            if (value & option) {
              values.push(option);
            }
          });
          return values;
        }),
        tap(() => {
          this.updateValidity();

          if (this.hasError) {
            this.toggle(true);
          }

          this._cdr.markForCheck();
        })
      );
    } else {
      this.notificationChannels$ = NEVER;
    }
  }

  setNotificationChannels(notificationChannels: NotificationChannel[]) {
    const notificationChannel = notificationChannels.reduce((val, current) => val | current, 0) as NotificationChannel;
    this.notificationChannelControl.setValue(notificationChannel);
    this.notificationChannelControl.markAsDirty();
    if (this.communicationDetails) {
      this.channelActionEvent.emit(notificationChannels);
    }
  }

  toggle(value?: boolean) {
    this.patchState({ open: value ?? !this.get((s) => s.open) });
  }

  updateValidity() {
    this.emailControl?.updateValueAndValidity();
    this.mobileControl?.updateValueAndValidity();
  }
}
