import { z } from "zod"

import { REDEMPTION } from "@/constants/booking"

import { ChildBedMapEnum } from "@/types/components/bookingWidget/enums"

export const bookingWidgetErrors = {
  AGE_REQUIRED: "AGE_REQUIRED",
  BED_CHOICE_REQUIRED: "BED_CHOICE_REQUIRED",
  CHILDREN_EXCEEDS_ADULTS: "CHILDREN_EXCEEDS_ADULTS",
  BOOKING_CODE_INVALID: "BOOKING_CODE_INVALID",
  REQUIRED: "REQUIRED",
  DESTINATION_REQUIRED: "DESTINATION_REQUIRED",
  MULTIROOM_BOOKING_CODE_UNAVAILABLE: "MULTIROOM_BOOKING_CODE_UNAVAILABLE",
  MULTIROOM_REWARD_NIGHT_UNAVAILABLE: "MULTIROOM_REWARD_NIGHT_UNAVAILABLE",
  CODE_VOUCHER_REWARD_NIGHT_UNAVAILABLE:
    "CODE_VOUCHER_REWARD_NIGHT_UNAVAILABLE",
} as const

export const guestRoomSchema = z
  .object({
    adults: z.number().default(1),
    childrenInRoom: z
      .array(
        z.object({
          age: z.number().min(0, bookingWidgetErrors.AGE_REQUIRED),
          bed: z.number().min(0, bookingWidgetErrors.BED_CHOICE_REQUIRED),
        })
      )
      .default([]),
  })
  .superRefine((value, ctx) => {
    const childrenInAdultsBed = value.childrenInRoom.filter(
      (c) => c.bed === ChildBedMapEnum.IN_ADULTS_BED
    )
    if (value.adults < childrenInAdultsBed.length) {
      const lastAdultBedIndex = value.childrenInRoom
        .map((c) => c.bed)
        .lastIndexOf(ChildBedMapEnum.IN_ADULTS_BED)

      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: bookingWidgetErrors.CHILDREN_EXCEEDS_ADULTS,
        path: ["childrenInRoom", lastAdultBedIndex],
      })
    }
  })

export const guestRoomsSchema = z.array(guestRoomSchema)

export const bookingCodeSchema = z
  .object({
    value: z
      .string()
      .refine(
        (value) =>
          !value ||
          /(^D\d*$)|(^DSH[0-9a-z]*$)|(^L\d*$)|(^LH[0-9a-z]*$)|(^B[a-z]{3}\d{6})|(^VO[0-9a-z]*$)|^[0-9a-z]*$/i.test(
            value
          ),
        { message: bookingWidgetErrors.BOOKING_CODE_INVALID }
      )
      .default(""),
    remember: z.boolean().default(false),
    flag: z.boolean().default(false),
  })
  .optional()

export const bookingWidgetSchema = z
  .object({
    bookingCode: bookingCodeSchema,
    date: z.object({
      // Update this as required once started working with Date picker in Nights component
      fromDate: z.string(),
      toDate: z.string(),
    }),
    redemption: z.boolean().default(false),
    rooms: guestRoomsSchema,
    search: z.string({ coerce: true }).min(1, bookingWidgetErrors.REQUIRED),
    selectedSearch: z.string().optional(),
    hotel: z.number().optional(),
    city: z.string().optional(),
  })
  .superRefine((value, ctx) => {
    if (!value.hotel && !value.city) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: bookingWidgetErrors.DESTINATION_REQUIRED,
        path: ["search"],
      })
    }
    if (value.rooms.length > 1 && value.bookingCode?.value.startsWith("VO")) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: bookingWidgetErrors.MULTIROOM_BOOKING_CODE_UNAVAILABLE,
        path: ["bookingCode.value"],
      })
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: bookingWidgetErrors.MULTIROOM_BOOKING_CODE_UNAVAILABLE,
        path: ["rooms"],
      })
    }
    if (value.rooms.length > 1 && value.redemption) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: bookingWidgetErrors.MULTIROOM_REWARD_NIGHT_UNAVAILABLE,
        path: [REDEMPTION],
      })
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: bookingWidgetErrors.MULTIROOM_REWARD_NIGHT_UNAVAILABLE,
        path: ["rooms"],
      })
    }
    if (value.bookingCode?.value && value.redemption) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: bookingWidgetErrors.CODE_VOUCHER_REWARD_NIGHT_UNAVAILABLE,
        path: [REDEMPTION],
      })
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: bookingWidgetErrors.CODE_VOUCHER_REWARD_NIGHT_UNAVAILABLE,
        path: ["bookingCode.value"],
      })
    }
  })
