import { z } from "zod"

import { MembershipLevelEnum } from "@/constants/membershipLevels"

import {
  linkRefsUnionSchema,
  linkUnionSchema,
  transformPageLink,
} from "../schemas/pageLinks"
import { systemSchema } from "../schemas/system"

export {
  BenefitReward,
  CouponData,
  CouponReward,
  REDEEM_LOCATIONS,
  REWARD_TYPES,
  rewardRefsSchema,
  validateApiAllTiersSchema,
  validateCategorizedRewardsSchema,
  validateCmsRewardsSchema,
}

const validateCmsRewardsSchema = z
  .object({
    data: z.object({
      all_reward: z.object({
        items: z.array(
          z.object({
            taxonomies: z.array(
              z.object({
                term_uid: z.string().optional().default(""),
              })
            ),
            label: z.string().optional(),
            reward_id: z.string(),
            grouped_label: z.string().optional(),
            description: z.string().optional(),
            redeem_description: z
              .object({
                json: z.any(), // JSON
                embedded_itemsConnection: z.object({
                  edges: z.array(
                    z.object({
                      node: linkUnionSchema.transform((data) => {
                        const link = transformPageLink(data)
                        if (link) {
                          return link
                        }
                        return data
                      }),
                    })
                  ),
                }),
              })
              // This is primarily added in order to handle a transition
              // switching from string to RTE
              .nullable(),
            grouped_description: z.string().optional(),
            value: z.string().optional(),
          })
        ),
      }),
    }),
  })
  .transform((data) => data.data.all_reward.items)

const rewardRefsSchema = z.object({
  data: z.object({
    all_reward: z.object({
      items: z.array(
        z.object({
          redeem_description: z
            .object({
              embedded_itemsConnection: z.object({
                edges: z.array(
                  z.object({
                    node: linkRefsUnionSchema,
                  })
                ),
              }),
            })
            // This is primarily added in order to handle a transition
            // switching from string to RTE
            .nullable(),
          system: systemSchema,
        })
      ),
    }),
  }),
})

const REDEEM_LOCATIONS = ["Non-redeemable", "On-site", "Online"] as const
const REWARD_CATEGORIES = [
  "Restaurants",
  "Bar",
  "Voucher",
  "Services and rooms",
  "Spa and gym",
] as const

const BaseReward = z.object({
  title: z.string().optional(),
  id: z.string(),
  categories: z
    .array(z.enum(REWARD_CATEGORIES).or(z.literal("")))
    .optional()
    // we sometimes receive empty categories, this filters them out
    .transform((categories = []) =>
      categories.filter(
        (c): c is (typeof REWARD_CATEGORIES)[number] => c !== ""
      )
    ),
  rewardId: z.string(),
  redeemLocation: z.enum(REDEEM_LOCATIONS),
  status: z.enum(["active", "expired"]),
})

const REWARD_TYPES = {
  Surprise: "Surprise",
  Campaign: "Campaign",
  MemberVoucher: "Member-voucher",
  Tier: "Tier",
} as const

const BenefitReward = BaseReward.merge(
  z.object({
    rewardType: z.enum([REWARD_TYPES.Tier]),
    rewardTierLevel: z.string().optional(),
  })
)

const CouponData = z.object({
  couponCode: z.string(),
  unwrapped: z.boolean().default(false),
  state: z.enum(["claimed", "redeemed", "viewed"]),
  expiresAt: z.string().datetime({ offset: true }).optional(),
})

const CouponReward = BaseReward.merge(
  z.object({
    rewardType: z.enum([
      REWARD_TYPES.Surprise,
      REWARD_TYPES.Campaign,
      REWARD_TYPES.MemberVoucher,
    ]),
    operaRewardId: z.string().default(""),
    coupon: z
      .array(CouponData)
      .optional()
      .transform((val) => val || []),
  })
)

const validateCategorizedRewardsSchema = z.object({
  benefits: z.array(BenefitReward),
  coupons: z.array(CouponReward),
})

const TierKeyMapping = {
  tier1: MembershipLevelEnum.L1,
  tier2: MembershipLevelEnum.L2,
  tier3: MembershipLevelEnum.L3,
  tier4: MembershipLevelEnum.L4,
  tier5: MembershipLevelEnum.L5,
  tier6: MembershipLevelEnum.L6,
  tier7: MembershipLevelEnum.L7,
} as const

const TierKeys = Object.keys(TierKeyMapping) as [keyof typeof TierKeyMapping]

const validateApiAllTiersSchema = z.record(
  z.enum(TierKeys).transform((data) => TierKeyMapping[data]),
  z.array(BenefitReward)
)
