/**
 * N8N Booking Validator
 *
 * Comprehensive Zod schemas for all N8N webhook endpoints:
 * - Create booking
 * - Check availability
 * - Booking actions (reschedule, cancel, payment, refund, etc.)
 *
 * @module lib/validators/n8n-booking.validator
 */

import { z } from 'zod';

// =============================================================================
// Common Schemas
// =============================================================================

/**
 * Date format regex (YYYY-MM-DD)
 */
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;

/**
 * Time format regex (HH:MM)
 */
const timeRegex = /^\d{2}:\d{2}$/;

/**
 * Customer information schema
 */
export const CustomerSchema = z.object({
  name: z.string().min(1, 'Customer name is required').max(200),
  phone: z.string().min(5, 'Valid phone number is required').max(20),
  email: z.string().email('Invalid email format').optional().nullable(),
});

export type CustomerInput = z.infer<typeof CustomerSchema>;

/**
 * Booking details schema for creation
 */
export const BookingDetailsSchema = z.object({
  service: z.string().min(1, 'Service name is required').max(200),
  date: z.string().regex(dateRegex, 'Date must be in YYYY-MM-DD format'),
  time: z.string().regex(timeRegex, 'Time must be in HH:MM format'),
  duration: z.number().min(15, 'Minimum duration is 15 minutes').max(480, 'Maximum duration is 8 hours').default(30),
  staff_member: z.string().max(200).optional().nullable(),
  notes: z.string().max(1000).optional().nullable(),
  total_amount: z.number().min(0).optional().default(0),
  deposit_amount: z.number().min(0).optional().nullable(),
  deposit_required: z.boolean().default(false),
});

export type BookingDetailsInput = z.infer<typeof BookingDetailsSchema>;

// =============================================================================
// Create Booking Schema
// =============================================================================

/**
 * Schema for POST /api/n8n/booking (create new booking)
 */
export const CreateBookingSchema = z.object({
  auth_token: z.string().min(1, 'Auth token is required'),
  organization_id: z.string().optional().nullable(),
  user_id: z.string().min(1, 'User ID is required'),
  conversation_id: z.string().optional().nullable(),
  source: z.enum(['whatsapp', 'voice', 'web', 'phone_call', 'manual'], {
    errorMap: () => ({
      message: "Source must be one of: whatsapp, voice, web, phone_call, manual",
    }),
  }).default('whatsapp'),
  customer: CustomerSchema,
  booking: BookingDetailsSchema,
});

export type CreateBookingInput = z.infer<typeof CreateBookingSchema>;

// =============================================================================
// Check Availability Schema
// =============================================================================

/**
 * Schema for POST /api/n8n/availability
 */
export const CheckAvailabilitySchema = z.object({
  auth_token: z.string().min(1, 'Auth token is required'),
  user_id: z.string().min(1, 'User ID is required'),
  organization_id: z.string().optional().nullable(),
  date: z.string().regex(dateRegex, 'Date must be in YYYY-MM-DD format'),
  service: z.string().optional(),
  staff_member: z.string().optional().nullable(),
  duration: z.number().min(15).max(480).default(30),
});

export type CheckAvailabilityInput = z.infer<typeof CheckAvailabilitySchema>;

// =============================================================================
// Unified Booking Action Schema (Extended)
// =============================================================================

/**
 * Extended action parameters for different booking operations
 */
export const BookingActionParamsSchema = z.object({
  // For reschedule action
  newDate: z
    .string()
    .regex(dateRegex, 'Date must be in YYYY-MM-DD format')
    .optional(),
  newTime: z
    .string()
    .regex(timeRegex, 'Time must be in HH:MM format')
    .optional(),
  // For cancel and refund actions
  reason: z.string().max(500).optional(),
  refund_reason: z.string().max(500).optional(),
  // For mark_paid action
  payment_reference: z.string().max(200).optional(),
  payment_method: z.enum(['cash', 'bank_transfer', 'card', 'other']).optional(),
}).optional().default({});

/**
 * Extended booking action schema with additional actions
 */
export const ExtendedBookingActionSchema = z.object({
  auth_token: z.string().min(1, 'Auth token is required'),
  booking_id: z.string().min(1, 'Booking ID is required'),
  action: z.enum([
    'reschedule',
    'cancel',
    'generate_payment_link',
    'refund',
    'mark_paid',
    'check_status',
  ], {
    errorMap: () => ({
      message: "Action must be one of: reschedule, cancel, generate_payment_link, refund, mark_paid, check_status",
    }),
  }),
  params: BookingActionParamsSchema,
});

export type ExtendedBookingActionInput = z.infer<typeof ExtendedBookingActionSchema>;

// =============================================================================
// Create Booking Action Schema (for unified endpoint with create)
// =============================================================================

/**
 * Customer and booking params for create action
 */
export const CreateActionParamsSchema = z.object({
  user_id: z.string().min(1, 'User ID is required'),
  organization_id: z.string().optional().nullable(),
  conversation_id: z.string().optional().nullable(),
  source: z.enum(['whatsapp', 'voice', 'web', 'phone_call', 'manual']).default('whatsapp'),
  customer: CustomerSchema,
  booking: BookingDetailsSchema,
});

export type CreateActionParamsInput = z.infer<typeof CreateActionParamsSchema>;

/**
 * Unified booking action schema that includes create action
 */
export const UnifiedBookingActionSchema = z.discriminatedUnion('action', [
  // Create action - booking_id not required
  z.object({
    auth_token: z.string().min(1, 'Auth token is required'),
    action: z.literal('create'),
    booking_id: z.string().optional().nullable(),
    params: CreateActionParamsSchema,
  }),
  // Other actions - booking_id required
  z.object({
    auth_token: z.string().min(1, 'Auth token is required'),
    action: z.enum(['reschedule', 'cancel', 'generate_payment_link', 'refund', 'mark_paid', 'check_status']),
    booking_id: z.string().min(1, 'Booking ID is required'),
    params: BookingActionParamsSchema,
  }),
]);

export type UnifiedBookingActionInput = z.infer<typeof UnifiedBookingActionSchema>;

// =============================================================================
// Outbound Webhook Event Schema
// =============================================================================

/**
 * Event types for outbound webhooks (Mawidi → n8n)
 */
export enum N8NEventType {
  BOOKING_CREATED = 'booking.created',
  BOOKING_UPDATED = 'booking.updated',
  BOOKING_CANCELLED = 'booking.cancelled',
  PAYMENT_RECEIVED = 'payment.received',
  PAYMENT_REFUNDED = 'payment.refunded',
  REMINDER_DUE = 'reminder.due',
}

/**
 * Outbound webhook payload schema
 */
export const OutboundWebhookPayloadSchema = z.object({
  event: z.nativeEnum(N8NEventType),
  timestamp: z.string().datetime(),
  booking_id: z.string(),
  user_id: z.string(),
  organization_id: z.string().optional().nullable(),
  data: z.record(z.unknown()),
});

export type OutboundWebhookPayload = z.infer<typeof OutboundWebhookPayloadSchema>;

// =============================================================================
// Availability Response Schema (for documentation)
// =============================================================================

/**
 * Available slot structure
 */
export const AvailableSlotSchema = z.object({
  time: z.string(),
  duration_available: z.number(),
  staff_available: z.array(z.string()).optional(),
});

export type AvailableSlot = z.infer<typeof AvailableSlotSchema>;

/**
 * Availability response schema
 */
export const AvailabilityResponseSchema = z.object({
  success: z.boolean(),
  date: z.string(),
  available_slots: z.array(AvailableSlotSchema),
  business_hours: z.object({
    open: z.string(),
    close: z.string(),
  }),
  timezone: z.string().default('Asia/Qatar'),
});

export type AvailabilityResponse = z.infer<typeof AvailabilityResponseSchema>;

// =============================================================================
// Booking Response Schema (for documentation)
// =============================================================================

/**
 * Standard booking action response
 */
export const BookingActionResponseSchema = z.object({
  success: z.boolean(),
  action: z.string().optional(),
  booking_id: z.string().optional(),
  data: z.record(z.unknown()).optional(),
  error: z.string().optional(),
});

export type BookingActionResponse = z.infer<typeof BookingActionResponseSchema>;
