import {
  Component,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Output,
  EventEmitter,
  Input,
  OnChanges,
  SimpleChanges,
} from '@angular/core';
import { CrmCustomerService } from '@domain/crm';
import { DomainOmsService } from '@domain/oms';
import { NotificationChannel } from '@generated/swagger/checkout-api';
import {
  KeyValueDTOOfStringAndString,
  OrderDTO,
  OrderItemListItemDTO,
} from '@generated/swagger/oms-api';
import { DateAdapter } from '@ui/common';
import { cloneDeep } from 'lodash';
import { BehaviorSubject, combineLatest } from 'rxjs';
import { filter, first, map, shareReplay, switchMap } from 'rxjs/operators';
import { CustomerOrderDetailsStore } from '../customer-order-details.store';
import { getEnabledCustomerFeature } from '@isa/crm/data-access';

@Component({
  selector: 'page-customer-order-details-header',
  templateUrl: 'customer-order-details-header.component.html',
  styleUrls: ['customer-order-details-header.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  standalone: false,
})
export class CustomerOrderDetailsHeaderComponent implements OnChanges {
  @Output()
  editClick = new EventEmitter<OrderItemListItemDTO>();

  @Output()
  handleAction = new EventEmitter<KeyValueDTOOfStringAndString>();

  @Input()
  order: OrderDTO;

  get isKulturpass() {
    return this.order?.features?.orderSource === 'KulturPass';
  }

  minDateDatepicker = this.dateAdapter.addCalendarDays(
    this.dateAdapter.today(),
    -1,
  );
  today = this.dateAdapter.today();

  selectedOrderItemCount$ = this._store.selectedeOrderItemSubsetIds$.pipe(
    map((ids) => ids?.length ?? 0),
  );

  orderItemCount$ = this._store.items$.pipe(map((items) => items?.length ?? 0));

  orderItem$ = this._store.items$.pipe(
    map((orderItems) => orderItems?.find((_) => true)),
  );

  preferredPickUpDate$ = new BehaviorSubject<Date>(undefined);

  notificationsChannel: NotificationChannel = 0;

  changeDateLoader$ = new BehaviorSubject<boolean>(false);
  changePreferredDateLoader$ = new BehaviorSubject<boolean>(false);
  changeStatusLoader$ = new BehaviorSubject<boolean>(false);
  changeStatusDisabled$ = this._store.changeActionDisabled$;
  changeDateDisabled$ = this.changeStatusDisabled$;

  customerFeature$ = this.orderItem$.pipe(
    filter((orderItem) => !!orderItem),
    switchMap((orderItem) =>
      this.customerService.getCustomers(orderItem.buyerNumber).pipe(
        map((res) =>
          res.result.find((c) => c.customerNumber === orderItem.buyerNumber),
        ),
        map((customer) => getEnabledCustomerFeature(customer?.features)),
      ),
    ),
    shareReplay(),
  );

  statusActions$ = this.orderItem$.pipe(
    map((orderItem) =>
      orderItem?.actions?.filter((action) => action.enabled === false),
    ),
  );

  showMultiselect$ = combineLatest([
    this._store.items$,
    this._store.fetchPartial$,
    this._store.itemsSelectable$,
  ]).pipe(
    map(
      ([orderItems, fetchPartial, multiSelect]) =>
        multiSelect && fetchPartial && orderItems?.length > 1,
    ),
  );

  crudaUpdate$ = this.orderItem$.pipe(
    map((orederItem) => !!(orederItem?.cruda & 4)),
  );

  editButtonDisabled$ = combineLatest([
    this.changeStatusLoader$,
    this.crudaUpdate$,
  ]).pipe(
    map(
      ([changeStatusLoader, crudaUpdate]) => changeStatusLoader || !crudaUpdate,
    ),
  );

  canEditStatus$ = combineLatest([this.statusActions$, this.crudaUpdate$]).pipe(
    map(
      ([statusActions, crudaUpdate]) =>
        statusActions?.length > 0 && crudaUpdate,
    ),
  );

  openAddresses = false;

  get digOrderNumber(): string {
    return this.order?.linkedRecords?.find((_) => true)?.number;
  }

  get showAddresses(): boolean {
    return (
      (this.order?.orderType === 2 || this.order?.orderType === 4) &&
      (!!this.order?.shipping || !!this.order?.billing)
    );
  }

  get showFeature(): boolean {
    return !!this.order?.features && !!this.order?.features?.orderType;
  }

  constructor(
    private _store: CustomerOrderDetailsStore,
    private customerService: CrmCustomerService,
    private dateAdapter: DateAdapter,
    private omsService: DomainOmsService,
    private cdr: ChangeDetectorRef,
  ) {}

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.order) {
      this.findLatestPreferredPickUpDate();
      this.computeNotificationChannel();
    }
  }

  computeNotificationChannel() {
    const order = this.order;
    this.notificationsChannel = order?.notificationChannels ?? 0;
    this.cdr.markForCheck();
  }

  async updatePickupDeadline(deadline: Date) {
    this.changeDateLoader$.next(true);
    this.changeStatusDisabled$.next(true);
    const orderItems = cloneDeep(this._store.items);
    for (const item of orderItems) {
      if (
        this.dateAdapter.compareDate(
          deadline,
          new Date(item.pickUpDeadline),
        ) !== 0
      ) {
        try {
          const res = await this.omsService
            .setPickUpDeadline(
              item.orderId,
              item.orderItemId,
              item.orderItemSubsetId,
              deadline?.toISOString(),
            )
            .pipe(first())
            .toPromise();
          item.pickUpDeadline = deadline.toISOString();
        } catch (error) {
          console.error(error);
        }
      }
    }
    this.changeDateLoader$.next(false);
    this.changeStatusDisabled$.next(false);
    this._store.updateOrderItems(orderItems);
  }

  async updateEstimatedShippingDate(estimatedShippingDate: Date) {
    this.changeDateLoader$.next(true);
    this.changeStatusDisabled$.next(true);
    const orderItems = cloneDeep(this._store.items);
    for (const item of orderItems) {
      if (
        this.dateAdapter.compareDate(
          estimatedShippingDate,
          new Date(item.pickUpDeadline),
        ) !== 0
      ) {
        try {
          const res = await this.omsService
            .setEstimatedShippingDate(
              item.orderId,
              item.orderItemId,
              item.orderItemSubsetId,
              estimatedShippingDate?.toISOString(),
            )
            .pipe(first())
            .toPromise();
          item.estimatedShippingDate = res.estimatedShippingDate;
        } catch (error) {
          console.error(error);
        }
      }
    }
    this.changeDateLoader$.next(false);
    this.changeStatusDisabled$.next(false);
    this._store.updateOrderItems(orderItems);
  }

  async handleActionClick(action: KeyValueDTOOfStringAndString) {
    this.changeStatusLoader$.next(true);
    this.handleAction.emit(action);
    setTimeout(() => this.changeStatusLoader$.next(false), 1000);
    this.cdr.markForCheck();
  }

  selectAll() {
    this._store.selectAllOrderItems();
  }

  async updatePreferredPickUpDate(date: Date) {
    this.changePreferredDateLoader$.next(true);
    this.changeStatusDisabled$.next(true);
    const orderItems = cloneDeep(this._store.items);

    const data: Record<string, string> = {};
    orderItems.forEach((item) => {
      data[`${item.orderItemSubsetId}`] = date?.toISOString();
    });

    try {
      await this.omsService.setPreferredPickUpDate({ data }).toPromise();
      this.order.items.forEach((item) => {
        item.data.subsetItems.forEach(
          (subsetItem) =>
            (subsetItem.data.preferredPickUpDate = date.toISOString()),
        );
      });
      this.findLatestPreferredPickUpDate();
    } catch (error) {
      console.error(error);
    }
    this.changePreferredDateLoader$.next(false);
    this.changeStatusDisabled$.next(false);
  }

  findLatestPreferredPickUpDate() {
    let latestDate;
    const subsetItems = this.order?.items
      ?.reduce((acc, item) => {
        return [...acc, ...item.data.subsetItems];
      }, [])
      ?.filter((a) => !!a.data.preferredPickUpDate);
    if (subsetItems?.length > 0) {
      latestDate = new Date(
        subsetItems?.reduce((a, b) => {
          return new Date(a.data.preferredPickUpDate) >
            new Date(b.data.preferredPickUpDate)
            ? a
            : b;
        })?.data?.preferredPickUpDate,
      );
    }
    this.preferredPickUpDate$.next(latestDate);
  }
}
