import { createSelector } from '@reduxjs/toolkit';
import { RootState } from '../../store';
import { selectRequestRooms } from '../booking/selectors';
import { isEmpty, sum } from 'lodash';
import { PriceDetailsPerPaxType, PricePerPaxType } from '../../types';
import { BookingPackageRequestRoom, BookingPriceDetail } from '@qite/tide-client';

export const selectPriceDetails = (state: RootState) => state.priceDetails.priceDetails;

export const selectPackagePriceDetails = createSelector(selectPriceDetails, (priceDetails) => priceDetails.filter((priceDetail) => priceDetail.isInPackage));

export const selectSeparatePackagePriceDetails = createSelector(selectPackagePriceDetails, (pricedetails) => {
  const result: BookingPriceDetail[] = [];
  const filteredPriceDetails = pricedetails.filter((priceDetail) => priceDetail.isSeparate);

  filteredPriceDetails.forEach((priceDetail) => {
    const priceDetailToMerge = result.find(
      (x) => x.productCode === priceDetail.productCode && x.accommodationCode === priceDetail.accommodationCode && x.productType === priceDetail.productType
    );
    if (priceDetailToMerge) {
      priceDetailToMerge.total += priceDetail.total;
      priceDetailToMerge.price += priceDetail.price;
    } else {
      result.push(Object.assign({}, priceDetail));
    }
  });

  return result;
});

export const selectBasePrice = createSelector(selectPackagePriceDetails, (priceDetails) =>
  sum(priceDetails.map((priceDetail) => priceDetail.price * priceDetail.amount))
);

export const selectSeparateExtraPriceDetails = createSelector(selectPriceDetails, (priceDetails) =>
  priceDetails.filter((priceDetail) => !priceDetail.isInPackage && priceDetail.isSeparate)
);

export const selectTotalPrice = createSelector(selectBasePrice, selectSeparateExtraPriceDetails, (basePrice, separatePriceDetails) =>
  sum([basePrice, ...separatePriceDetails.map((priceDetail) => priceDetail.price * priceDetail.amount)])
);

// Shared function to aggregate price and details per paxType
const aggregatePricePerPaxType = (priceDetails: BookingPriceDetail[], requestRooms: BookingPackageRequestRoom[] | undefined): PricePerPaxType[] => {
  if (!requestRooms || isEmpty(requestRooms)) return [];
  if (!priceDetails || isEmpty(priceDetails)) return [];

  // Compute paxType by age: >=2 INFANT, >=11 CHILD, else ADULT
  const paxTypeToPaxIds: Record<string, Set<number>> = {};
  requestRooms.forEach((room) => {
    room.pax.forEach((pax) => {
      let paxType = 'ADULT';
      if (typeof pax.age === 'number') {
        if (pax.age <= 11 && pax.age > 2) {
          paxType = 'CHILD';
        } else if (pax.age <= 2) {
          paxType = 'INFANT';
        }
      }
      if (!paxTypeToPaxIds[paxType]) paxTypeToPaxIds[paxType] = new Set();
      paxTypeToPaxIds[paxType].add(pax.id);
    });
  });

  const result: PricePerPaxType[] = [];

  Object.keys(paxTypeToPaxIds).forEach((paxType) => {
    const paxIds = Array.from(paxTypeToPaxIds[paxType]);
    let pricePerPaxType = 0;
    const detailsMap: Record<string, PriceDetailsPerPaxType> = {};

    priceDetails.forEach((detail) => {
      if (!detail.showPrice || !detail.pricePerPax) return;
      detail.pricePerPax.forEach((ppp) => {
        if (paxIds.includes(ppp.paxId)) {
          pricePerPaxType += ppp.price;
          const descKey = detail.priceDescription || '';
          if (!detailsMap[descKey]) {
            detailsMap[descKey] = {
              numberOfPax: 1,
              description: detail.priceDescription || '',
              price: ppp.price,
              paxIds: [ppp.paxId]
            } as PriceDetailsPerPaxType;
          } else {
            detailsMap[descKey].price += ppp.price;
            if (!detailsMap[descKey].paxIds.includes(ppp.paxId)) {
              detailsMap[descKey].paxIds.push(ppp.paxId);
              detailsMap[descKey].numberOfPax += 1;
            }
          }
        }
      });
    });

    result.push({
      paxType,
      pricePerPaxType,
      numberOfPax: paxIds.length,
      details: Object.values(detailsMap)
    });
  });

  return result;
};

export const selectBasePricePerPaxType = createSelector(selectPackagePriceDetails, selectRequestRooms, (priceDetails, requestRooms) =>
  aggregatePricePerPaxType(priceDetails, requestRooms)
);

export const selectSeparateExtraPriceDetailsPerPaxType = createSelector(selectSeparateExtraPriceDetails, selectRequestRooms, (priceDetails, requestRooms) =>
  aggregatePricePerPaxType(priceDetails, requestRooms)
);

export const selectDeposit = (state: RootState) => state.priceDetails.deposit;
export const selectCommission = (state: RootState) => state.priceDetails.commission;

export const selectIsFetchingPriceDetails = (state: RootState) => state.priceDetails.isBusy;
