import { computed, effect, inject, Injectable, untracked } from '@angular/core';
import {
  SelectedRewardShoppingCartResource,
  SelectedShoppingCartResource,
  ShoppingCartItem,
  getOrderTypeFeature,
  RewardSelectionItem,
  itemSelectionChanged,
  mergeRewardSelectionItems,
} from '@isa/checkout/data-access';
import { injectDialog } from '@isa/ui/dialog';
import {
  RewardSelectionDialogComponent,
  RewardSelectionDialogResult,
} from '../reward-selection-dialog.component';
import { PrimaryCustomerCardResource } from '@isa/crm/data-access';
import { firstValueFrom } from 'rxjs';
import { toObservable } from '@angular/core/rxjs-interop';
import { debounceTime, filter } from 'rxjs/operators';
import {
  PriceAndRedemptionPointsResource,
  ItemWithOrderType,
} from '../resource/price-and-redemption-points.resource';

@Injectable()
export class RewardSelectionService {
  rewardSelectionDialog = injectDialog(RewardSelectionDialogComponent);

  #primaryCustomerCardResource = inject(PrimaryCustomerCardResource);
  #priceAndRedemptionPointsResource = inject(PriceAndRedemptionPointsResource);
  #shoppingCartResource = inject(SelectedShoppingCartResource).resource;
  #rewardShoppingCartResource = inject(SelectedRewardShoppingCartResource)
    .resource;

  readonly shoppingCartResponseValue =
    this.#shoppingCartResource.value.asReadonly();

  readonly rewardShoppingCartResponseValue =
    this.#rewardShoppingCartResource.value.asReadonly();

  readonly primaryCustomerCardValue =
    this.#primaryCustomerCardResource.primaryCustomerCard;

  readonly priceAndRedemptionPoints =
    this.#priceAndRedemptionPointsResource.priceAndRedemptionPoints;

  shoppingCartItems = computed(() => {
    return (
      this.shoppingCartResponseValue()
        ?.items?.map((item) => item?.data as ShoppingCartItem)
        .filter((item): item is ShoppingCartItem => item != null) ?? []
    );
  });

  rewardShoppingCartItems = computed(() => {
    return (
      this.rewardShoppingCartResponseValue()
        ?.items?.map((item) => item?.data as ShoppingCartItem)
        .filter((item): item is ShoppingCartItem => item != null) ?? []
    );
  });

  mergedRewardSelectionItems = computed<RewardSelectionItem[]>(() => {
    return mergeRewardSelectionItems(
      this.shoppingCartItems(),
      this.rewardShoppingCartItems(),
    );
  });

  selectionItemsWithOrderType = computed<ItemWithOrderType[]>(() => {
    return this.mergedRewardSelectionItems()
      .map((item): ItemWithOrderType | null => {
        const ean = item.item.product.ean;
        const orderType = getOrderTypeFeature(item.item.features);
        const branchId = item.item.destination?.data?.targetBranch?.data?.id;

        if (!ean || !orderType) {
          return null;
        }

        return { ean, orderType, branchId };
      })
      .filter((item): item is ItemWithOrderType => item !== null);
  });

  updatedRewardSelectionItems = computed<RewardSelectionItem[]>(() => {
    const rewardSelectionItems = this.mergedRewardSelectionItems();
    const priceAndRedemptionResults = this.priceAndRedemptionPoints();

    return rewardSelectionItems.map((selectionItem) => {
      const ean = selectionItem.item.product.ean;
      const result = priceAndRedemptionResults?.find((r) => r.ean === ean);

      return {
        ...selectionItem,
        catalogPrice: result?.catalogPrice,
        catalogRewardPoints: result?.redemptionPoints,
        availabilityPrice: result?.availabilityPrice,
      };
    });
  });

  primaryBonusCardPoints = computed(
    () => this.primaryCustomerCardValue()?.totalPoints ?? 0,
  );

  isLoading = computed(
    () =>
      this.#shoppingCartResource.isLoading() ||
      this.#rewardShoppingCartResource.isLoading() ||
      this.#primaryCustomerCardResource.loading() ||
      this.#priceAndRedemptionPointsResource.loading(),
  );
  #isLoading$ = toObservable(this.isLoading);

  eligibleItems = computed(() =>
    this.updatedRewardSelectionItems().filter(
      (selectionItem) =>
        (selectionItem.item.loyalty?.value != null &&
          selectionItem.item.loyalty.value !== 0) ||
        (selectionItem?.catalogRewardPoints != null &&
          selectionItem.catalogRewardPoints !== 0),
    ),
  );

  canOpen = computed(
    () => this.eligibleItems().length > 0 && !!this.primaryBonusCardPoints(),
  );

  constructor() {
    effect(() => {
      const items = this.selectionItemsWithOrderType();

      untracked(() => {
        const resourceLoading =
          this.#priceAndRedemptionPointsResource.loading();

        if (!resourceLoading && items.length > 0) {
          this.#priceAndRedemptionPointsResource.loadPriceAndRedemptionPoints(
            items,
          );
        }
      });
    });
  }

  async open({
    closeText,
  }: {
    closeText: string;
  }): Promise<RewardSelectionDialogResult> {
    const rewardSelectionItems = this.eligibleItems();
    const dialogRef = this.rewardSelectionDialog({
      title: 'Ein oder mehrere Artikel sind als Prämie verfügbar',
      data: {
        rewardSelectionItems,
        customerRewardPoints: this.primaryBonusCardPoints(),
        closeText,
      },
      displayClose: true,
      disableClose: false,
      width: '44.5rem',
    });
    const dialogResult = await firstValueFrom(dialogRef.closed);

    if (
      itemSelectionChanged(
        rewardSelectionItems,
        dialogResult?.rewardSelectionItems,
      )
    ) {
      await this.reloadResources();
      return dialogResult;
    }

    return undefined;
  }

  async reloadResources(): Promise<void> {
    this.#shoppingCartResource.reload();
    this.#rewardShoppingCartResource.reload();
    // Wait until all resources are fully loaded (isLoading becomes false)
    await firstValueFrom(
      this.#isLoading$.pipe(
        debounceTime(50),
        filter((isLoading) => !isLoading),
      ),
    );
  }
}
