import { z } from "zod"

import { ChildBedTypeEnum } from "@/constants/booking"
import { Lang, langToApiLang } from "@/constants/languages"

const roomsSchema = z
  .array(
    z.object({
      adults: z.number().int().nonnegative(),
      bookingCode: z.string().nullish(),
      childrenAges: z
        .array(
          z.object({
            age: z.number().int().nonnegative(),
            bedType: z.nativeEnum(ChildBedTypeEnum),
          })
        )
        .default([]),
      rateCode: z.string(),
      redemptionCode: z.string().optional(),
      roomTypeCode: z.coerce.string(),
      guest: z.object({
        becomeMember: z.boolean(),
        countryCode: z.string(),
        dateOfBirth: z.string().nullish(),
        email: z.string().email(),
        firstName: z.string(),
        lastName: z.string(),
        membershipNumber: z.string().nullish(),
        postalCode: z.string().nullish(),
        phoneNumber: z.string(),
      }),
      smsConfirmationRequested: z.boolean(),
      specialRequest: z.object({
        comment: z.string().optional(),
      }),
      packages: z.object({
        breakfast: z.boolean(),
        allergyFriendly: z.boolean(),
        petFriendly: z.boolean(),
        accessibility: z.boolean(),
      }),
      roomPrice: z.object({
        memberPrice: z.number().nullish(),
        publicPrice: z.number().nullish(),
      }),
    })
  )
  .superRefine((data, ctx) => {
    data.forEach((room, idx) => {
      if (idx === 0 && room.guest.becomeMember) {
        if (!room.guest.dateOfBirth) {
          ctx.addIssue({
            code: z.ZodIssueCode.invalid_type,
            expected: "string",
            received: typeof room.guest.dateOfBirth,
            path: ["guest", "dateOfBirth"],
          })
        }

        if (!room.guest.postalCode) {
          ctx.addIssue({
            code: z.ZodIssueCode.invalid_type,
            expected: "string",
            received: typeof room.guest.postalCode,
            path: ["guest", "postalCode"],
          })
        }
      }
    })
  })

const paymentSchema = z.object({
  paymentMethod: z.string(),
  card: z
    .object({
      alias: z.string(),
      expiryDate: z.string(),
      cardType: z.string(),
    })
    .optional(),
  cardHolder: z
    .object({
      email: z.string().email(),
      name: z.string(),
      phoneCountryCode: z.string(),
      phoneSubscriber: z.string(),
    })
    .optional(),
  success: z.string(),
  error: z.string(),
  cancel: z.string(),
})

// Mutation
export const createBookingInput = z.object({
  hotelId: z.string(),
  checkInDate: z.string(),
  checkOutDate: z.string(),
  rooms: roomsSchema,
  payment: paymentSchema.optional(),
  language: z.nativeEnum(Lang).transform((val) => langToApiLang[val]),
})

export const addPackageInput = z.object({
  ancillaryComment: z.string(),
  ancillaryDeliveryTime: z.string().nullish(),
  packages: z.array(
    z.object({
      code: z.string(),
      quantity: z.number(),
      comment: z.string().optional(),
    })
  ),
  language: z.nativeEnum(Lang).transform((val) => langToApiLang[val]),
})

export const removePackageInput = z.object({
  codes: z.array(z.string()),
  language: z.nativeEnum(Lang).transform((val) => langToApiLang[val]),
})

export const cancelBookingsInput = z.object({
  language: z.nativeEnum(Lang),
})

export const guaranteeBookingInput = z.object({
  card: z
    .object({
      alias: z.string(),
      expiryDate: z.string(),
      cardType: z.string(),
    })
    .optional(),
  language: z.nativeEnum(Lang).transform((val) => langToApiLang[val]),
  success: z.string().nullable(),
  error: z.string().nullable(),
  cancel: z.string().nullable(),
})

export const createRefIdInput = z.object({
  confirmationNumber: z
    .string()
    .trim()
    .regex(/^\s*[0-9]+(-[0-9])?\s*$/)
    .min(1),
  lastName: z.string().trim().max(250).min(1),
})

export const updateBookingInput = z.object({
  checkInDate: z.string().optional(),
  checkOutDate: z.string().optional(),
  guest: z
    .object({
      email: z.string().optional(),
      phoneNumber: z.string().optional(),
      countryCode: z.string().optional(),
    })
    .optional(),
  language: z.nativeEnum(Lang).transform((val) => langToApiLang[val]),
})

// Query

export const getBookingInput = z.object({
  lang: z.nativeEnum(Lang).optional(),
})

export const getLinkedReservationsInput = z.object({
  lang: z.nativeEnum(Lang).optional(),
})

export const findBookingInput = z.object({
  confirmationNumber: z.string(),
  firstName: z.string(),
  lastName: z.string(),
  email: z.string(),
  lang: z.nativeEnum(Lang).optional(),
})

export type LinkedReservationsInput = z.input<typeof getLinkedReservationsInput>

export const getBookingStatusInput = z.object({
  lang: z.nativeEnum(Lang).optional(),
})
