import {
  Component,
  ChangeDetectionStrategy,
  OnInit,
  OnDestroy,
  inject,
} from '@angular/core';
import { CustomerSearchStore } from '../../store';
import { CrmCustomerService } from '@domain/crm';
import { map, switchMap, takeUntil } from 'rxjs/operators';
import { Observable, Subject, combineLatest } from 'rxjs';
import {
  ListResponseArgsOfAssignedPayerDTO,
  ShippingAddressDTO,
} 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 { CrmTabMetadataService, Customer } from '@isa/crm/data-access';
import { injectTabId } from '@isa/core/tabs';
import { ShippingAddressAdapter } from '@isa/checkout/data-access';

interface DetailsMainViewDeliveryAddressesComponentState {
  shippingAddresses: ShippingAddressDTO[];
  selectedShippingAddress: ShippingAddressDTO;
}

@Component({
  selector: 'page-details-main-view-delivery-addresses',
  templateUrl: 'details-main-view-delivery-addresses.component.html',
  styleUrls: ['details-main-view-delivery-addresses.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: { class: 'page-details-main-view-delivery-addresses' },
  imports: [AsyncPipe, CustomerPipesModule, RouterLink],
})
export class DetailsMainViewDeliveryAddressesComponent
  extends ComponentStore<DetailsMainViewDeliveryAddressesComponentState>
  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);

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

  selectedShippingAddress$ = this.select(
    (state) => state.selectedShippingAddress,
  );

  get selectedShippingAddress() {
    return this.get((s) => s.selectedShippingAddress);
  }

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

  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;
  }

  customer$ = this._store.customer$;

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

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

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

  editShippingAddressRoute$ = (shippingAddressId: number) =>
    combineLatest([
      this.canEditAddress$,
      this._store.processId$,
      this._store.customerId$,
    ]).pipe(
      map(([canEditAddress, processId, customerId]) => {
        if (canEditAddress) {
          return this._navigation.editShippingAddressRoute({
            processId,
            customerId,
            shippingAddressId,
          });
        }
        return undefined;
      }),
    );

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

  constructor() {
    super({
      shippingAddresses: [],
      selectedShippingAddress: undefined,
    });
  }

  ngOnInit() {
    this._store.customerId$
      .pipe(takeUntil(this._onDestroy$))
      .subscribe((customerId) => {
        this.resetStore();
        if (customerId) {
          this.loadShippingAddresses(customerId);
        }
      });

    combineLatest([this.selectedShippingAddress$, this._store.customer$])
      .pipe(takeUntil(this._onDestroy$))
      .subscribe(([selectedShippingAddress, customer]) => {
        if (selectedShippingAddress) {
          this._host.setShippingAddress(
            ShippingAddressAdapter.fromCrmShippingAddress(
              selectedShippingAddress,
            ),
          );
          this.crmTabMetadataService.setSelectedShippingAddressId(
            this.tabId(),
            selectedShippingAddress?.id,
          );
        } else if (this.showCustomerAddress) {
          this._host.setShippingAddress(
            ShippingAddressAdapter.fromCustomer(
              customer as unknown as Customer,
            ),
          );
          // Clear the selected shipping address ID when using customer address
          this.crmTabMetadataService.setSelectedShippingAddressId(
            this.tabId(),
            undefined,
          );
        }
      });
  }

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

  loadShippingAddresses = this.effect((customerId$: Observable<number>) =>
    customerId$.pipe(
      switchMap((customerId) =>
        this._customerService
          .getShippingAddresses({ customerId })
          .pipe(
            tapResponse(
              this.handleLoadShippingAddressesResponse,
              this.handleLoadAssignedPayersError,
            ),
          ),
      ),
    ),
  );

  handleLoadShippingAddressesResponse = (
    response: ListResponseArgsOfAssignedPayerDTO,
  ) => {
    const selectedShippingAddress = response.result.reduce<ShippingAddressDTO>(
      (prev, curr) => {
        if (!this.showCustomerAddress && !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({
      shippingAddresses: response.result,
      selectedShippingAddress,
    });
  };

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

  resetStore() {
    this.patchState({
      shippingAddresses: [],
      selectedShippingAddress: undefined,
    });
  }

  selectShippingAddress(shippingAddress: ShippingAddressDTO) {
    this.patchState({
      selectedShippingAddress: shippingAddress,
    });
  }

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