import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { ControlContainer, FormControl, UntypedFormGroup } from '@angular/forms';
import { ComponentStore } from '@ngrx/component-store';
import { CommunicationDetailsDTO } from '@generated/swagger/checkout-api';
import { NotificationChannel } from '@generated/swagger/oms-api';
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'],
  standalone: false,
})
export class SharedNotificationChannelControlComponent
  extends ComponentStore<SharedNotificationChannelControlComponentState>
  implements OnInit
{
  notificationGroup: UntypedFormGroup;

  @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') as FormControl;
  }

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

  get emailDisabled() {
    return this.channelActionLoading || this.emailControl?.errors?.required || this.emailControl?.errors?.pattern;
  }

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

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

  get mobileDisabled() {
    return this.channelActionLoading || this.mobileControl?.errors?.required || this.mobileControl?.errors?.pattern;
  }

  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 UntypedFormGroup) {
      this.notificationGroup = this._notificationsGroup.control;
    }
    this.initNotificationChannels$();
  }

  showChannelActionNameForEmailControl() {
    return (!!this.channelActionName && this.emailControl?.dirty) || this.showSendAgainActionForEmail();
  }

  showChannelActionNameForMobileControl() {
    return (!!this.channelActionName && this.mobileControl?.dirty) || this.showSendAgainActionForMobile();
  }

  clear(control: FormControl) {
    control.setValue('');
    control.markAsDirty();
    this._cdr.markForCheck();
  }

  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 = this.getNotificationChannel(notificationChannels);
    this.notificationChannelControl.setValue(notificationChannel);
    this.notificationChannelControl.markAsDirty();
    if (this.communicationDetails) {
      this.channelActionEvent.emit(notificationChannels);
    }
  }

  getNotificationChannel(notificationChannels?: NotificationChannel[]) {
    let nfc = notificationChannels ?? this.notificationChannels;
    return nfc.reduce((val, current) => val | current, 0) as NotificationChannel;
  }

  // Ticket #4526 RD // Bearbeiten - erneut senden Button fehlt
  // Auf den Pickup Shelf Edit Seiten soll der Erneut senden button immer ersichtlich sein
  showSendAgainActionForEmail() {
    return this.channelActionName === 'Erneut senden' && (this.getNotificationChannel() as number) !== 3;
  }

  // Ticket #4526 RD // Bearbeiten - erneut senden Button fehlt
  // Auf den Pickup Shelf Edit Seiten soll der Erneut senden button immer ersichtlich sein
  // Wenn die Felder Email und SMS angehakt wurden, soll der Button nur einmal angezeigt werden
  showSendAgainActionForMobile() {
    return (
      this.channelActionName === 'Erneut senden' &&
      (this.getNotificationChannel() === 2 || this.getNotificationChannel() !== 1)
    );
  }

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

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

  save() {
    this.channelActionEvent.emit(this.notificationChannels);
    this.emailControl?.markAsPristine();
    this.mobileControl?.markAsPristine();
    this._cdr.markForCheck();
  }
}
