import {
  Component,
  ChangeDetectionStrategy,
  Host,
  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 {
  DBHOrderItemListItemDTO,
  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 { SharedGoodsInOutOrderDetailsComponent } from '../goods-in-out-order-details.component';
import { Config } from '@core/config';
import { coerceArray } from '@angular/cdk/coercion';

@Component({
  selector: 'shared-goods-in-out-order-details-header',
  templateUrl: 'goods-in-out-order-details-header.component.html',
  styleUrls: ['goods-in-out-order-details-header.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  standalone: false,
})
export class SharedGoodsInOutOrderDetailsHeaderComponent implements OnChanges {
  @Output()
  editClick = new EventEmitter<DBHOrderItemListItemDTO>();

  @Input()
  order: OrderDTO;

  @Input()
  selectedOrderItemId: number;

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

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

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

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

  orderItem$ = this.host.orderItems$.pipe(map((orderItems) => orderItems[0]));

  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.host.changeActionDisabled$;
  changeDateDisabled$ = this.changeStatusDisabled$;

  features$ = 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) => customer?.features || []),
        map((features) => features.filter((f) => f.enabled && !!f.description)),
      ),
    ),
    shareReplay(),
  );

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

  showMultiselect$ = combineLatest([this.host.orderItems$, this.host.fetchPartial$, this.host.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: boolean = 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;
  }

  preferredPickUpDateDisabled$ = combineLatest([this.changeDateDisabled$, this.orderItem$]).pipe(
    map(([changeDateDisabled, orderItem]) => {
      if (changeDateDisabled) {
        return true;
      }

      if ((orderItem?.orderItemType & 1024) === 1024) {
        return true;
      }

      return !this.isKulturpass && !!orderItem?.features?.paid;
    }),
  );

  vslLieferdatumDisabled$ = combineLatest([this.changeDateDisabled$, this.orderItem$]).pipe(
    map(([changeDateDisabled, orderItem]) => {
      if (changeDateDisabled) {
        return true;
      }

      return (orderItem?.orderItemType & 1024) === 1024;
    }),
  );

  constructor(
    @Host() private host: SharedGoodsInOutOrderDetailsComponent,
    private customerService: CrmCustomerService,
    private dateAdapter: DateAdapter,
    private omsService: DomainOmsService,
    private cdr: ChangeDetectorRef,
    private config: Config,
  ) {}

  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.host.orderItems);
    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.host.updateOrderItems(orderItems);
  }

  async updateEstimatedShippingDate(estimatedShippingDate: Date) {
    this.changeDateLoader$.next(true);
    this.changeStatusDisabled$.next(true);
    const orderItems = cloneDeep(this.host.orderItems);
    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.host.updateOrderItems(orderItems);
  }

  async handleAction(action: KeyValueDTOOfStringAndString) {
    this.changeStatusLoader$.next(true);
    try {
      await this.host.handleAction(action);
    } catch (error) {
      console.error(error);
    }

    setTimeout(() => this.changeStatusLoader$.next(false), 1000);
    this.cdr.markForCheck();
  }

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

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

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

    try {
      await this.omsService.setPreferredPickUpDate({ data }).toPromise();
      this.order.items.forEach((item) => {
        item.data.subsetItems
          .filter((item) => !this.selectedOrderItemId || this.selectedOrderItemId === item.data.id)
          .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 && (!this.selectedOrderItemId || this.selectedOrderItemId === a.data.id),
      );
    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);
  }
}
