import { z } from 'zod'
import { bilingualPrimary } from '@/components/ui/BilingualInput'
import type { FieldErrors, ReservationDraft } from './reservationWizard.types'
import type { ReservationWizardCopy } from './reservationWizard.copy'

const MAX_IMAGE_BYTES = 5 * 1024 * 1024
const IMAGE_TYPES = new Set(['image/jpeg', 'image/png', 'image/webp', 'image/gif', 'image/heic', 'image/heif'])

function nonEmpty(message: string) {
  return z.string().trim().min(1, message)
}

function emailSchema(copy: ReservationWizardCopy) {
  return nonEmpty(copy.validation.required).email(copy.validation.email)
}

function dateInPast(value: string) {
  if (!value) return false
  const date = new Date(value)
  return Number.isFinite(date.getTime()) && date < new Date()
}

function addIssue(ctx: z.RefinementCtx, path: string[], message: string) {
  ctx.addIssue({ code: z.ZodIssueCode.custom, path, message })
}

export function validateCustomerStep(draft: ReservationDraft, copy: ReservationWizardCopy): FieldErrors {
  const schema = z.object({
    mode: z.enum(['existing', 'new']),
    selectedCustomerId: z.string().nullable(),
    firstName: z.any(),
    lastName: z.any(),
    email: z.string(),
    phone: z.string(),
  }).superRefine((customer, ctx) => {
    if (customer.mode === 'existing') {
      if (!customer.selectedCustomerId) addIssue(ctx, ['selectedCustomerId'], copy.validation.required)
      return
    }
    if (!bilingualPrimary(customer.firstName).trim()) addIssue(ctx, ['firstName'], copy.validation.required)
    if (!bilingualPrimary(customer.lastName).trim()) addIssue(ctx, ['lastName'], copy.validation.required)
    if (!emailSchema(copy).safeParse(customer.email).success) addIssue(ctx, ['email'], customer.email.trim() ? copy.validation.email : copy.validation.required)
    if (!customer.phone.trim()) addIssue(ctx, ['phone'], copy.validation.required)
  })
  return zodErrors(schema.safeParse(draft.customer), 'customer')
}

export function validateIdentityStep(draft: ReservationDraft, copy: ReservationWizardCopy): FieldErrors {
  const schema = z.object({
    dateOfBirth: nonEmpty(copy.validation.required),
    nationality: nonEmpty(copy.validation.required),
    fullAddress: nonEmpty(copy.validation.required),
    identityDocumentNumber: nonEmpty(copy.validation.required),
    internationalLicenseNumber: z.string(),
  }).superRefine((identity, ctx) => {
    if (identity.dateOfBirth && !dateInPast(identity.dateOfBirth)) addIssue(ctx, ['dateOfBirth'], copy.validation.pastDate)
  })
  return zodErrors(schema.safeParse(draft.identity), 'identity')
}

export function validateLicenseStep(draft: ReservationDraft, copy: ReservationWizardCopy): FieldErrors {
  const schema = z.object({
    number: nonEmpty(copy.validation.required),
    country: nonEmpty(copy.validation.required),
    issuedAt: nonEmpty(copy.validation.required),
    expiry: nonEmpty(copy.validation.required),
    category: nonEmpty(copy.validation.required),
    newImageFile: z.any().nullable(),
  }).superRefine((license, ctx) => {
    const issuedAt = new Date(license.issuedAt)
    const expiry = new Date(license.expiry)
    const now = new Date()
    if (license.issuedAt && issuedAt > now) addIssue(ctx, ['issuedAt'], copy.validation.futureIssue)
    if (license.issuedAt && license.expiry && expiry <= issuedAt) addIssue(ctx, ['expiry'], copy.validation.expiryAfterIssue)
    if (license.expiry && expiry <= now) addIssue(ctx, ['expiry'], copy.validation.expiryFuture)
    if (typeof File !== 'undefined' && license.newImageFile instanceof File) {
      if (!IMAGE_TYPES.has(license.newImageFile.type)) addIssue(ctx, ['newImageFile'], copy.validation.imageType)
      if (license.newImageFile.size > MAX_IMAGE_BYTES) addIssue(ctx, ['newImageFile'], copy.validation.imageSize)
    }
  })
  return zodErrors(schema.safeParse(draft.license), 'license')
}

export function validateRentalStep(draft: ReservationDraft, copy: ReservationWizardCopy): FieldErrors {
  const schema = z.object({
    vehicleId: nonEmpty(copy.validation.required),
    startDate: nonEmpty(copy.validation.required),
    endDate: nonEmpty(copy.validation.required),
    pickupLocation: z.string(),
    returnLocation: z.string(),
  }).superRefine((rental, ctx) => {
    if (rental.startDate && rental.endDate && new Date(rental.endDate) <= new Date(rental.startDate)) {
      addIssue(ctx, ['endDate'], copy.validation.endAfterStart)
    }
  })
  return zodErrors(schema.safeParse(draft.rental), 'rental')
}

export function validatePaymentExtrasStep(draft: ReservationDraft, copy: ReservationWizardCopy): FieldErrors {
  const errors: FieldErrors = {}
  const deposit = Number(draft.payment.depositAmount)
  if (!Number.isFinite(deposit) || deposit < 0) errors['payment.depositAmount'] = copy.validation.deposit
  if (!draft.payment.paymentMode.trim()) errors['payment.paymentMode'] = copy.validation.required
  draft.additionalDrivers.forEach((driver, index) => {
    if (!bilingualPrimary(driver.firstName).trim()) errors[`additionalDrivers.${index}.firstName`] = copy.validation.required
    if (!bilingualPrimary(driver.lastName).trim()) errors[`additionalDrivers.${index}.lastName`] = copy.validation.required
    if (!driver.driverLicense.trim()) errors[`additionalDrivers.${index}.driverLicense`] = copy.validation.required
    if (driver.licenseIssuedAt && new Date(driver.licenseIssuedAt) > new Date()) {
      errors[`additionalDrivers.${index}.licenseIssuedAt`] = copy.validation.futureIssue
    }
    if (driver.licenseIssuedAt && driver.licenseExpiry && new Date(driver.licenseExpiry) <= new Date(driver.licenseIssuedAt)) {
      errors[`additionalDrivers.${index}.licenseExpiry`] = copy.validation.expiryAfterIssue
    }
    if (driver.dateOfBirth && !dateInPast(driver.dateOfBirth)) {
      errors[`additionalDrivers.${index}.dateOfBirth`] = copy.validation.pastDate
    }
  })
  return errors
}

export function validateCompleteReservation(draft: ReservationDraft, copy: ReservationWizardCopy): FieldErrors {
  return {
    ...validateCustomerStep(draft, copy),
    ...validateIdentityStep(draft, copy),
    ...validateLicenseStep(draft, copy),
    ...validateRentalStep(draft, copy),
    ...validatePaymentExtrasStep(draft, copy),
  }
}

function zodErrors(result: z.SafeParseReturnType<unknown, unknown>, prefix: string): FieldErrors {
  if (result.success) return {}
  return result.error.issues.reduce<FieldErrors>((errors, issue) => {
    const path = issue.path.length > 0 ? `${prefix}.${issue.path.join('.')}` : prefix
    errors[path] = issue.message
    return errors
  }, {})
}
