import {
  Component,
  ChangeDetectionStrategy,
  OnInit,
  OnDestroy,
  inject,
} from '@angular/core';
import { CustomerSearchStore } from '../../store';
import { CrmCustomerService } from '@domain/crm';
import { debounceTime, map, switchMap, takeUntil } from 'rxjs/operators';
import { Observable, Subject, combineLatest } from 'rxjs';
import {
  AssignedPayerDTO,
  ListResponseArgsOfAssignedPayerDTO,
} from '@generated/swagger/crm-api';
import { AsyncPipe } from '@angular/common';
import { CustomerPipesModule } from '@shared/pipes/customer';
import { ComponentStore } from '@ngrx/component-store';
import { tapResponse } from '@ngrx/operators';

import { UiModalService } from '@ui/modal';
import { CustomerSearchNavigation } from '@shared/services/navigation';
import { RouterLink } from '@angular/router';
import { CustomerDetailsViewMainComponent } from '../details-main-view.component';
import {
  AssignedPayer,
  CrmTabMetadataService,
  Customer,
} from '@isa/crm/data-access';
import { injectTabId } from '@isa/core/tabs';
import { CustomerAdapter } from '@isa/checkout/data-access';

interface DetailsMainViewBillingAddressesComponentState {
  assignedPayers: AssignedPayerDTO[];
  selectedPayer: AssignedPayerDTO;
}

@Component({
  selector: 'page-details-main-view-billing-addresses',
  templateUrl: 'details-main-view-billing-addresses.component.html',
  styleUrls: ['details-main-view-billing-addresses.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: { class: 'page-details-main-view-billing-addresses' },
  imports: [AsyncPipe, CustomerPipesModule, RouterLink],
})
export class DetailsMainViewBillingAddressesComponent
  extends ComponentStore<DetailsMainViewBillingAddressesComponentState>
  implements OnInit, OnDestroy
{
  tabId = injectTabId();
  crmTabMetadataService = inject(CrmTabMetadataService);

  private _host = inject(CustomerDetailsViewMainComponent, { host: true });
  private _store = inject(CustomerSearchStore);
  private _customerService = inject(CrmCustomerService);
  private _modal = inject(UiModalService);
  private _navigation = inject(CustomerSearchNavigation);

  assignedPayers$ = this.select((state) => state.assignedPayers);

  selectedPayer$ = this.select((state) => state.selectedPayer);

  isNotBusinessKonto$ = this._store.isBusinessKonto$.pipe(
    map((isBusinessKonto) => !isBusinessKonto),
  );

  showCustomerAddress$ = combineLatest([
    this._store.isBusinessKonto$,
    this._store.isMitarbeiter$,
    this._store.isKundenkarte$,
  ]).pipe(
    map(
      ([isBusinessKonto, isMitarbeiter, isKundenkarte]) =>
        isBusinessKonto || isMitarbeiter || isKundenkarte,
    ),
  );

  get showCustomerAddress() {
    return this._store.isBusinessKonto || this._store.isMitarbeiter;
  }

  canAddNewAddress$ = combineLatest([
    this._store.isOnlinekonto$,
    this._store.isOnlineKontoMitKundenkarte$,
    this._store.isKundenkarte$,
  ]).pipe(
    map(
      ([isOnlinekonto, isOnlineKontoMitKundenkarte, isKundenkarte]) =>
        isOnlinekonto || isOnlineKontoMitKundenkarte || isKundenkarte,
    ),
  );

  canEditAddress$ = combineLatest([this._store.isKundenkarte$]).pipe(
    map(([isKundenkarte]) => isKundenkarte),
  );

  customer$ = this._store.customer$;

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

  editRoute$ = combineLatest([
    this._store.processId$,
    this._store.customerId$,
    this._store.isBusinessKonto$,
  ]).pipe(
    map(([processId, customerId, isB2b]) =>
      this._navigation.editRoute({ processId, customerId, isB2b }),
    ),
  );

  addBillingAddressRoute$ = combineLatest([
    this.canAddNewAddress$,
    this._store.processId$,
    this._store.customerId$,
  ]).pipe(
    map(([canAddNewAddress, processId, customerId]) =>
      canAddNewAddress
        ? this._navigation.addBillingAddressRoute({ processId, customerId })
        : undefined,
    ),
  );

  constructor() {
    super({
      assignedPayers: [],
      selectedPayer: undefined,
    });
  }

  editRoute(payerId: number) {
    return this._navigation.editBillingAddressRoute({
      customerId: this._store.customerId,
      payerId,
      processId: this._store.processId,
    });
  }

  ngOnInit() {
    combineLatest([this._store.customerId$, this._store.isMitarbeiter$])
      .pipe(takeUntil(this._onDestroy$), debounceTime(250))
      .subscribe(([customerId, isMitarbeiter]) => {
        this.resetStore();
        // #4715 Hier erfolgt ein Check auf Mitarbeiter, da Mitarbeiter keine zusätzlichen Rechnungsadressen haben sollen
        if (customerId && !isMitarbeiter) {
          this.loadAssignedPayers(customerId);
        }
      });

    combineLatest([this.selectedPayer$, this._store.customer$])
      .pipe(takeUntil(this._onDestroy$))
      .subscribe(([selectedPayer, customer]) => {
        if (selectedPayer) {
          const payer = CustomerAdapter.toPayerFromAssignedPayer(
            selectedPayer as AssignedPayer,
          );
          if (payer) {
            this._host.setPayer(payer);
            this.crmTabMetadataService.setSelectedPayerId(
              this.tabId(),
              selectedPayer?.payer?.id,
            );
          }
        } else if (this.showCustomerAddress) {
          this._host.setPayer(
            CustomerAdapter.toPayerFromCustomer(
              customer as unknown as Customer,
            ),
          );
        }
      });
  }

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

  loadAssignedPayers = this.effect((customerId$: Observable<number>) =>
    customerId$.pipe(
      switchMap((customerId) =>
        this._customerService
          .getAssignedPayers({ customerId })
          .pipe(
            tapResponse(
              this.handleLoadAssignedPayersResponse,
              this.handleLoadAssignedPayersError,
            ),
          ),
      ),
    ),
  );

  handleLoadAssignedPayersResponse = (
    response: ListResponseArgsOfAssignedPayerDTO,
  ) => {
    const selectedPayer = response.result.reduce<AssignedPayerDTO>(
      (prev, curr) => {
        if (!prev) {
          return curr;
        }

        const prevDate = new Date(prev?.isDefault ?? 0);
        const currDate = new Date(curr?.isDefault ?? 0);

        if (prevDate > currDate) {
          return prev;
        }

        return curr;
      },
      undefined,
    );

    this.patchState({
      assignedPayers: response.result,
      selectedPayer,
    });
  };

  handleLoadAssignedPayersError = (err: unknown) => {
    this._modal.error(
      'Laden der Rechnungsadressen fehlgeschlagen',
      err as Error,
    );
  };

  resetStore() {
    this.patchState({
      assignedPayers: [],
      selectedPayer: undefined,
    });
  }

  selectPayer(payer: AssignedPayerDTO) {
    this.patchState({
      selectedPayer: payer,
    });
  }

  selectCustomerAddress() {
    this.patchState({
      selectedPayer: undefined,
    });
  }
}
