import { CdkTextareaAutosize, TextFieldModule } from '@angular/cdk/text-field';
import {
  AsyncPipe,
  CurrencyPipe,
  DatePipe,
  DecimalPipe,
} from '@angular/common';
import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  EventEmitter,
  Input,
  Output,
  ViewChild,
  inject,
  OnDestroy,
} from '@angular/core';
import {
  FormsModule,
  ReactiveFormsModule,
  UntypedFormControl,
} from '@angular/forms';
import {
  NavigateOnClickDirective,
  ProductImageModule,
} from '@cdn/product-image';
import {
  DBHOrderItemListItemDTO,
  OrderDTO,
  ReceiptDTO,
} from '@generated/swagger/oms-api';
import { getOrderItemRewardFeature } from '@isa/oms/data-access';
import { UiCommonModule } from '@ui/common';
import { LabelComponent } from '@isa/ui/label';
import { UiTooltipModule } from '@ui/tooltip';
import { PickupShelfPaymentTypePipe } from '../pipes/payment-type.pipe';
import { IconModule } from '@shared/components/icon';
import { ComponentStore } from '@ngrx/component-store';
import { isEqual } from 'lodash';
import { map, switchMap } from 'rxjs/operators';
import { Subject, combineLatest } from 'rxjs';
import { PickupShelfDetailsStore } from '../../store';
import { UiQuantityDropdownModule } from '@ui/quantity-dropdown';
import { NotificationTypePipe } from './notification-type.pipe';
import { MatomoModule } from 'ngx-matomo-client';

export interface PickUpShelfDetailsItemComponentState {
  orderItem?: DBHOrderItemListItemDTO;
  order?: OrderDTO;
  quantity?: number;
  selected?: boolean;
  more: boolean;
}

@Component({
  selector: 'page-pickup-shelf-details-item',
  templateUrl: 'pickup-shelf-details-item.component.html',
  styleUrls: ['pickup-shelf-details-item.component.scss'],
  host: { class: 'page-pickup-shelf-details-item' },
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    UiCommonModule,
    UiTooltipModule,
    FormsModule,
    ReactiveFormsModule,
    CurrencyPipe,
    DatePipe,
    DecimalPipe,
    AsyncPipe,
    ProductImageModule,
    TextFieldModule,
    PickupShelfPaymentTypePipe,
    IconModule,
    UiQuantityDropdownModule,
    NotificationTypePipe,
    NavigateOnClickDirective,
    MatomoModule,
    LabelComponent,
  ],
})
export class PickUpShelfDetailsItemComponent
  extends ComponentStore<PickUpShelfDetailsItemComponentState>
  implements OnDestroy
{
  private _store = inject(PickupShelfDetailsStore);

  @ViewChild('autosize') autosize: CdkTextareaAutosize;

  @Output()
  historyClick = new EventEmitter<DBHOrderItemListItemDTO>();

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

  @Input()
  get orderItem() {
    return this.get((s) => s.orderItem);
  }
  set orderItem(orderItem: DBHOrderItemListItemDTO) {
    if (!isEqual(this.orderItem, orderItem)) {
      // Remove Prev OrderItem from selected list
      if (this.orderItem?.orderItemSubsetId !== orderItem?.orderItemSubsetId) {
        this._store.selectOrderItem(this.orderItem, false);
      }

      this.patchState({
        orderItem,
        quantity: orderItem?.quantity,
        more: false,
      });
      this.specialCommentControl.reset(orderItem?.specialComment);
      // Add New OrderItem to selected list if selected was set to true by its input
      if (this.get((s) => s.selected)) {
        this._store.selectOrderItem(this.orderItem, true);
      }
    }
  }

  orderItems$ = this.select((s) => s.orderItem);

  @Input()
  get order() {
    return this.get((s) => s.order);
  }
  set order(order: OrderDTO) {
    this.patchState({ order });
  }

  readonly orderItem$ = this.select((s) => s.orderItem);

  emailNotificationDates$ = this.orderItem$.pipe(
    switchMap((orderItem) =>
      this._store.getEmailNotificationDate$(orderItem?.orderItemSubsetId),
    ),
  );

  hasEmailNotification$ = this.emailNotificationDates$.pipe(
    map((dates) => dates?.length > 0),
  );

  smsNotificationDates$ = this.orderItem$.pipe(
    switchMap((orderItem) =>
      this._store.getSmsNotificationDate$(orderItem?.orderItemSubsetId),
    ),
  );

  hasSmsNotification$ = this.smsNotificationDates$.pipe(
    map((dates) => dates?.length > 0),
  );

  /**
   * Observable that indicates whether the order item has reward points (Lesepunkte).
   * Returns true if the item has a 'praemie' feature.
   */
  hasRewardPoints$ = this.orderItem$.pipe(
    map((orderItem) => getOrderItemRewardFeature(orderItem) !== undefined),
  );

  /**
   * Observable that emits the reward points (Lesepunkte) value for the order item.
   * Returns the parsed numeric value from the 'praemie' feature, or undefined if not present.
   */
  rewardPoints$ = this.orderItem$.pipe(
    map((orderItem) => getOrderItemRewardFeature(orderItem)),
  );

  canChangeQuantity$ = combineLatest([
    this.orderItem$,
    this._store.fetchPartial$,
  ]).pipe(
    map(
      ([item, partialPickup]) =>
        ([16, 8192].includes(item?.processingStatus) || partialPickup) &&
        item.quantity > 1,
    ),
  );

  get quantity() {
    return this.get((s) => s.quantity);
  }
  set quantity(quantity: number) {
    if (this.quantity !== quantity) {
      this.patchState({ quantity });
      this._store.setSelectedOrderItemQuantity({
        orderItemSubsetId: this.orderItem.orderItemSubsetId,
        quantity,
      });
    }
  }

  readonly quantity$ = this.select((s) => s.quantity);

  @Input()
  get selected() {
    return this._store.selectedOrderItemIds.includes(
      this.orderItem?.orderItemSubsetId,
    );
  }
  set selected(selected: boolean) {
    if (this.selected !== selected) {
      this.patchState({ selected });
      this._store.selectOrderItem(this.orderItem, selected);
    }
  }

  readonly selected$ = combineLatest([
    this.orderItem$,
    this._store.selectedOrderItemIds$,
  ]).pipe(
    map(([orderItem, selectedItems]) =>
      selectedItems.includes(orderItem?.orderItemSubsetId),
    ),
  );

  @Output()
  selectedChange = new EventEmitter<boolean>();

  get isItemSelectable() {
    return this._store.orderItems?.some(
      (item) => !!item?.actions && item?.actions?.length > 0,
    );
  }

  get selectable() {
    return (
      this.isItemSelectable &&
      this._store.orderItems.length > 1 &&
      this._store.fetchPartial
    );
  }

  readonly selectable$ = combineLatest([
    this._store.orderItems$,
    this._store.fetchPartial$,
  ]).pipe(
    map(
      ([orderItems, fetchPartial]) =>
        orderItems.length > 1 && this.isItemSelectable && fetchPartial,
    ),
  );

  get receipts() {
    return this._store.receipts;
  }

  set receipts(receipts: ReceiptDTO[]) {
    this._store.updateReceipts(receipts);
  }

  readonly receipts$ = this._store.receipts$;

  readonly receiptCount$ = this.receipts$.pipe(
    map((receipts) => receipts?.length),
  );

  specialCommentControl = new UntypedFormControl();

  more$ = this.select((s) => s.more);

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

  expanded = false;

  constructor(private _cdr: ChangeDetectorRef) {
    super({
      more: false,
    });
  }

  ngOnDestroy() {
    // Remove Prev OrderItem from selected list
    this._store.selectOrderItem(this.orderItem, false);
    this._onDestroy$.next();
    this._onDestroy$.complete();
  }

  saveSpecialComment() {
    this.specialCommentChanged.emit(this.specialCommentControl.value ?? '');
  }

  setMore(more: boolean) {
    this.patchState({ more });
    if (more && this.receipts.length === 0) {
      this._store.loadReceipts(this.orderItem);
    }
  }

  setSelected(selected: boolean) {
    this.selected = selected;
    this.selectedChange.emit(selected);
    this._cdr.markForCheck();
  }

  orderItemFeature(orderItemListItem: DBHOrderItemListItemDTO) {
    const orderItems = this.order?.items;
    return orderItems?.find(
      (orderItem) => orderItem.data.id === orderItemListItem.orderItemId,
    )?.data?.features?.orderType;
  }

  triggerResize() {
    this.autosize.reset();
  }
}
