import { sumPackages } from "@/components/HotelReservation/utils"

import type { Price } from "@/types/components/hotelReservation/price"
import type { Rate } from "@/types/components/hotelReservation/selectRate/selectRate"
import { CurrencyEnum } from "@/types/enums/currency"
import type { Packages } from "@/types/requests/packages"
import type { RedemptionProduct } from "@/types/trpc/routers/hotel/roomAvailability"

export function calculateTotalPrice(
  selectedRateSummary: Rate[],
  isUserLoggedIn: boolean
) {
  return selectedRateSummary.reduce<Price>(
    (total, room, idx) => {
      if (!("member" in room.product) || !("public" in room.product)) {
        return total
      }

      const roomNr = idx + 1
      const isMainRoom = roomNr === 1
      let rate
      if (isUserLoggedIn && isMainRoom && room.product.member) {
        rate = room.product.member
      } else if (room.product.public) {
        rate = room.product.public
      }

      if (!rate) {
        return total
      }

      const packagesPrice = room.packages.reduce(
        (total, pkg) => {
          total.local = total.local + pkg.localPrice.totalPrice
          if (pkg.requestedPrice.totalPrice) {
            total.requested = total.requested + pkg.requestedPrice.totalPrice
          }
          return total
        },
        { local: 0, requested: 0 }
      )

      total.local.currency = rate.localPrice.currency
      total.local.price =
        total.local.price + rate.localPrice.pricePerStay + packagesPrice.local

      if (rate.localPrice.regularPricePerStay) {
        total.local.regularPrice =
          (total.local.regularPrice || 0) +
          rate.localPrice.regularPricePerStay +
          packagesPrice.local
      }

      if (rate.requestedPrice) {
        if (!total.requested) {
          total.requested = {
            currency: rate.requestedPrice.currency,
            price: 0,
          }
        }

        if (!total.requested.currency) {
          total.requested.currency = rate.requestedPrice.currency
        }

        total.requested.price =
          total.requested.price +
          rate.requestedPrice.pricePerStay +
          packagesPrice.requested

        if (rate.requestedPrice.regularPricePerStay) {
          total.requested.regularPrice =
            (total.requested.regularPrice || 0) +
            rate.requestedPrice.regularPricePerStay +
            packagesPrice.requested
        }
      }

      return total
    },
    {
      local: {
        currency: CurrencyEnum.Unknown,
        price: 0,
        regularPrice: undefined,
      },
      requested: undefined,
    }
  )
}

export function calculateRedemptionTotalPrice(
  redemption: RedemptionProduct["redemption"],
  packages: Packages | null
) {
  const pkgsSum = sumPackages(packages)
  let additionalPrice
  if (redemption.localPrice.additionalPricePerStay) {
    additionalPrice =
      redemption.localPrice.additionalPricePerStay + pkgsSum.price
  } else if (pkgsSum.price) {
    additionalPrice = pkgsSum.price
  }

  let additionalPriceCurrency
  if (redemption.localPrice.currency) {
    additionalPriceCurrency = redemption.localPrice.currency
  } else if (pkgsSum.currency) {
    additionalPriceCurrency = pkgsSum.currency
  }
  return {
    local: {
      additionalPrice,
      additionalPriceCurrency,
      currency: CurrencyEnum.POINTS,
      price: redemption.localPrice.pointsPerStay,
    },
  }
}

export function calculateVoucherPrice(selectedRateSummary: Rate[]) {
  return selectedRateSummary.reduce<Price>(
    (total, room) => {
      if (!("voucher" in room.product)) {
        return total
      }
      const rate = room.product.voucher

      total.local.price = total.local.price + rate.numberOfVouchers

      const pkgsSum = sumPackages(room.packages)
      if (pkgsSum.price && pkgsSum.currency) {
        total.local.additionalPrice =
          (total.local.additionalPrice || 0) + pkgsSum.price
        total.local.additionalPriceCurrency = pkgsSum.currency
      }

      return total
    },
    {
      local: {
        currency: CurrencyEnum.Voucher,
        price: 0,
      },
      requested: undefined,
    }
  )
}

export function calculateCorporateChequePrice(selectedRateSummary: Rate[]) {
  return selectedRateSummary.reduce<Price>(
    (total, room) => {
      if (!("corporateCheque" in room.product)) {
        return total
      }
      const rate = room.product.corporateCheque
      const pkgsSum = sumPackages(room.packages)

      total.local.price = total.local.price + rate.localPrice.numberOfCheques
      if (rate.localPrice.additionalPricePerStay) {
        total.local.additionalPrice =
          (total.local.additionalPrice || 0) +
          rate.localPrice.additionalPricePerStay +
          pkgsSum.price
      } else if (pkgsSum.price) {
        total.local.additionalPrice =
          (total.local.additionalPrice || 0) + pkgsSum.price
      }
      if (rate.localPrice.currency) {
        total.local.additionalPriceCurrency = rate.localPrice.currency
      }

      if (rate.requestedPrice) {
        if (!total.requested) {
          total.requested = {
            currency: CurrencyEnum.CC,
            price: 0,
          }
        }

        total.requested.price =
          total.requested.price + rate.requestedPrice.numberOfCheques

        if (rate.requestedPrice.additionalPricePerStay) {
          total.requested.additionalPrice =
            (total.requested.additionalPrice || 0) +
            rate.requestedPrice.additionalPricePerStay
        }

        if (rate.requestedPrice.currency) {
          total.requested.additionalPriceCurrency = rate.requestedPrice.currency
        }
      }

      return total
    },
    {
      local: {
        currency: CurrencyEnum.CC,
        price: 0,
      },
      requested: undefined,
    }
  )
}

export function getTotalPrice(
  mainRoomProduct: Rate | null,
  rateSummary: Array<Rate | null>,
  isUserLoggedIn: boolean
): Price | null {
  const summaryArray = rateSummary.filter((rate): rate is Rate => rate !== null)

  if (summaryArray.some((rate) => "corporateCheque" in rate.product)) {
    return calculateCorporateChequePrice(summaryArray)
  }

  if (!mainRoomProduct) {
    return calculateTotalPrice(summaryArray, isUserLoggedIn)
  }

  const { packages, product } = mainRoomProduct

  // In case of reward night (redemption) or voucher only single room booking is supported by business rules
  if ("redemption" in product) {
    return calculateRedemptionTotalPrice(product.redemption, packages)
  }
  if ("voucher" in product) {
    return calculateVoucherPrice(summaryArray)
  }

  return calculateTotalPrice(summaryArray, isUserLoggedIn)
}
