import {
  Component,
  ChangeDetectionStrategy,
  forwardRef,
  OnInit,
  Input,
  ChangeDetectorRef,
  OnDestroy,
  Output,
  EventEmitter,
  ViewChildren,
  QueryList,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { CacheService } from '@core/cache';
import { DomainCheckoutService } from '@domain/checkout';
import { ComponentStore } from '@ngrx/component-store';
import { tapResponse } from '@ngrx/operators';

import { OptionDTO } from '@generated/swagger/checkout-api';
import { UiCheckboxComponent } from '@ui/checkbox';
import { first, isBoolean, isString } from 'lodash';
import { combineLatest, Observable, Subject } from 'rxjs';
import {
  distinctUntilChanged,
  filter,
  map,
  shareReplay,
  switchMap,
} from 'rxjs/operators';

export interface CustomerTypeSelectorState {
  processId: number;
  customerType: string;
  p4mUser: boolean;
  options: OptionDTO[];
}

@Component({
  selector: 'app-customer-type-selector',
  templateUrl: 'customer-type-selector.component.html',
  styleUrls: ['customer-type-selector.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CustomerTypeSelectorComponent),
      multi: true,
    },
  ],
  standalone: false,
})
export class CustomerTypeSelectorComponent
  extends ComponentStore<CustomerTypeSelectorState>
  implements OnInit, OnDestroy, ControlValueAccessor
{
  @ViewChildren(UiCheckboxComponent)
  checkboxes: QueryList<UiCheckboxComponent>;

  private _onDestroy$ = new Subject<void>();

  @Input()
  readonly: boolean;

  @Input()
  get value() {
    // if (this.p4mUser) {
    //   return `${this.customerType}-p4m`;
    // }
    return this.customerType;
  }
  set value(value: string) {
    // if (value.includes('-p4m')) {
    //   this.p4mUser = true;
    //   this.customerType = value.replace('-p4m', '');
    // } else {
    this.customerType = value;
    // }
  }

  @Output()
  valueChanges = new EventEmitter<string>();

  @Input()
  disabled: boolean;

  @Input()
  set processId(val: number) {
    if (this.processId !== val) {
      this.patchState({ processId: val });
      this.getOptions(val);
    }
  }
  get processId() {
    return this.get((s) => s.processId);
  }

  @Input()
  get p4mUser() {
    return this.get((s) => s.p4mUser);
  }
  set p4mUser(val: boolean) {
    this.patchState({ p4mUser: val ?? false });
  }

  @Input()
  get customerType() {
    return this.get((s) => s.customerType);
  }
  set customerType(val: string) {
    this.patchState({ customerType: val });
  }

  @Input()
  p4mReadonly = false;

  get filteredOptions$() {
    const options$ = this.select((s) => s.options).pipe(distinctUntilChanged());
    const p4mUser$ = this.select((s) => s.p4mUser).pipe(distinctUntilChanged());
    const customerType$ = this.select((s) => s.customerType).pipe(
      distinctUntilChanged(),
    );
    return combineLatest([options$, p4mUser$, customerType$]).pipe(
      filter(([options]) => options?.length > 0),
      map(([options, p4mUser, customerType]) => {
        const initial = {
          p4mUser: this.p4mUser,
          customerType: this.customerType,
        };
        let result: OptionDTO[] = options;
        // if (p4mUser) {
        //   result = result.filter((o) => o.value === 'store' || (o.value === 'webshop' && o.enabled !== false));

        //   result = result.map((o) => {
        //     if (o.value === 'store') {
        //       return { ...o, enabled: false };
        //     }
        //     return o;
        //   });
        // }

        if (customerType === 'b2b' && this.p4mUser) {
          this.p4mUser = false;
        }

        if (initial.customerType !== this.customerType) {
          // if (initial.p4mUser !== this.p4mUser || initial.customerType !== this.customerType) {
          // this.setValue({ customerType: this.customerType, p4mUser: this.p4mUser });
          this.setValue({ customerType: this.customerType });
        }

        return result;
      }),
      shareReplay(1),
    );
  }

  get enabledOptions() {
    return this.get((s) => s.options.filter((o) => o.enabled !== false));
  }

  onChange = (value: string) => {};
  onTouched = () => {};

  constructor(
    private _checkoutService: DomainCheckoutService,
    private _cache: CacheService,
    private _cdr: ChangeDetectorRef,
  ) {
    super({
      processId: undefined,
      customerType: undefined,
      p4mUser: false,
      options: [],
    });
    this.initOptions();
  }

  async initOptions() {
    const options = await this._cache.get('customerTypeOptions');
    if (options) {
      this.patchState({ options });
    }
  }

  ngOnInit(): void {}

  getOptions = this.effect((processId$: Observable<number>) => {
    return processId$.pipe(
      switchMap((pid) =>
        this._checkoutService.canSetCustomer({ processId: pid }).pipe(
          tapResponse(
            (res) => {
              const options = res.create.options.values;
              this.patchState({ options });
              this._cache.set('customerTypeOptions', options);
            },
            (err) => {},
          ),
        ),
      ),
    );
  });

  ngOnDestroy(): void {
    this._onDestroy$.next();
    this._onDestroy$.complete();
  }

  writeValue(obj: any): void {
    this.value = obj;
    this._cdr.markForCheck();
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  setDisabledState?(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  // #4610 Checkbox welche bereits ausgewählt ist soll nicht abgewählt werden können (Ausnahme bei Kundenkarte + Onlinekonto)
  isOptionDisabled(option: OptionDTO) {
    const isValueCurrentlySelected = option.value === this.customerType;
    const isCustomerCardActive = this.p4mUser;
    return this.readonly || (isValueCurrentlySelected && !isCustomerCardActive);
  }

  setValue(value: { p4mUser?: boolean; customerType?: string } | string) {
    const initial = { p4mUser: this.p4mUser, customerType: this.customerType };

    if (typeof value === 'string') {
      this.value = value;
    } else {
      // if (isBoolean(value.p4mUser)) {
      //   this.p4mUser = value.p4mUser;
      // }
      if (isString(value.customerType)) {
        this.customerType = value.customerType;
      }
      // else if (this.p4mUser) {
      //   // Implementierung wie im PBI #3467 beschrieben
      //   // wenn customerType nicht gesetzt wird und p4mUser true ist,
      //   // dann customerType auf store setzen.
      //   // wenn dies nicht möglich ist da der Warenkob keinen store Kunden zulässt,
      //   // dann customerType auf webshop setzen.
      //   // wenn dies nicht möglich ist da der Warenkob keinen webshop Kunden zulässt,
      //   // dann customerType auf den ersten verfügbaren setzen und p4mUser auf false setzen.
      //   if (this.enabledOptions.some((o) => o.value === 'store')) {
      //     this.customerType = 'store';
      //   } else if (this.enabledOptions.some((o) => o.value === 'webshop')) {
      //     this.customerType = 'webshop';
      //   } else {
      //     this.p4mUser = false;
      //     const includesGuest = this.enabledOptions.some((o) => o.value === 'guest');
      //     this.customerType = includesGuest ? 'guest' : first(this.enabledOptions)?.value;
      //   }
      // }
      else {
        // wenn customerType nicht gesetzt wird und p4mUser false ist,
        // dann customerType auf den ersten verfügbaren setzen der nicht mit dem aktuellen customerType übereinstimmt.
        this.customerType =
          first(
            this.enabledOptions.filter((o) => o.value === this.customerType),
          )?.value ?? this.customerType;
      }
    }

    if (
      this.customerType !== initial.customerType ||
      this.p4mUser !== initial.p4mUser
    ) {
      this.onChange(this.value);
      this.onTouched();
      this.valueChanges.emit(this.value);
    }

    this.checkboxes
      ?.find((c) => c.name === this.customerType)
      ?.writeValue(true);
  }
}
