import { RESTAURANT_REWARD_IDS, REWARD_IDS } from "@/constants/rewards"
import { dt } from "@/lib/dt"

import type { Dayjs } from "dayjs"

import type {
  RestaurantRewardId,
  RewardId,
} from "@/types/components/myPages/rewards"
import type {
  ApiReward,
  RedeemableCoupon,
  RedeemLocation,
  SurpriseReward,
} from "@/types/trpc/routers/contentstack/reward"

export {
  getEarliestExpirationDate,
  getFirstRedeemableCoupon,
  getRedeemableRewards,
  getReedemableCoupons,
  getUnwrappedSurpriseRewards,
  isOnSiteTierReward,
  isRestaurantOnSiteTierReward,
  isRestaurantReward,
  isSurpriseReward,
  isTierType,
  isValidRewardId,
  redeemLocationIsOnSite,
}

function isValidRewardId(id: string): id is RewardId {
  return Object.values<string>(REWARD_IDS).includes(id)
}

function isRestaurantReward(rewardId: string): rewardId is RestaurantRewardId {
  return RESTAURANT_REWARD_IDS.some((id) => id === rewardId)
}

function redeemLocationIsOnSite(
  location: RedeemLocation
): location is "On-site" {
  return location === "On-site"
}

function isTierType(type: string): type is "Tier" {
  return type === "Tier"
}

function isOnSiteTierReward(reward: ApiReward): boolean {
  return (
    redeemLocationIsOnSite(reward.redeemLocation) &&
    isTierType(reward.rewardType)
  )
}

function isRestaurantOnSiteTierReward(reward: ApiReward): boolean {
  return isOnSiteTierReward(reward) && isRestaurantReward(reward.rewardId)
}

function getReedemableCoupons(reward: ApiReward): RedeemableCoupon[] {
  if ("coupon" in reward) {
    return reward.coupon.filter(
      (coupon): coupon is RedeemableCoupon => coupon.state !== "redeemed"
    )
  }
  return []
}

function getFirstRedeemableCoupon(reward: ApiReward): RedeemableCoupon {
  const sortedCoupons = getReedemableCoupons(reward).sort((a, b) => {
    // null values used instead of undefined, otherwise it will return current time
    return dt(a.expiresAt ?? null).valueOf() - dt(b.expiresAt ?? null).valueOf()
  })
  return sortedCoupons[0]
}

function getEarliestExpirationDate(reward: ApiReward) {
  return getReedemableCoupons(reward)
    .map(({ expiresAt }) => expiresAt)
    .filter((expiresAt): expiresAt is string => !!expiresAt)
    .reduce((earliestDate: Dayjs | null, expiresAt) => {
      const expiresAtDate = dt(expiresAt)
      if (!earliestDate) {
        return expiresAtDate
      }

      return earliestDate.isBefore(expiresAtDate) ? earliestDate : expiresAtDate
    }, null)
}

function isSurpriseReward(reward: ApiReward): reward is SurpriseReward {
  return reward.rewardType === "Surprise"
}

function getUnwrappedSurpriseRewards(rewards: ApiReward[]) {
  return rewards
    .filter(isSurpriseReward)
    .filter((reward) => getReedemableCoupons(reward).length)
    .filter((reward) => {
      const unwrappedCoupons =
        reward.coupon.filter((coupon) => !coupon.unwrapped) || []

      return unwrappedCoupons.length
    })
}

function getRedeemableRewards(rewards: ApiReward[]) {
  return rewards
    .filter((reward) => {
      if ("coupon" in reward && reward.coupon.length > 0) {
        if (reward.coupon.every((coupon) => coupon.state === "redeemed")) {
          return false
        }
      }
      return true
    })
    .filter((reward) => {
      if (isSurpriseReward(reward)) {
        return !reward.coupon.some(({ unwrapped }) => !unwrapped)
      }
      return true
    })
}
