/**
 * API Input Validation Schemas
 *
 * Centralized Zod schemas for API route input validation.
 * All API routes should use these schemas to validate input BEFORE any business logic.
 *
 * Usage:
 * ```typescript
 * import { contactSubmitSchema, validateBody } from '@/lib/validators/api-schemas';
 *
 * export async function POST(request: Request) {
 *   const validation = await validateBody(request, contactSubmitSchema);
 *   if (!validation.success) {
 *     return Response.json({ error: validation.error }, { status: 400 });
 *   }
 *   const data = validation.data;
 *   // ... continue with validated data
 * }
 * ```
 */

import { z } from 'zod';
import { getSectorCustomFields } from '@/lib/config/sector-custom-fields';

// =============================================================================
// Common Validation Patterns
// =============================================================================

/** Email validation with sanitization */
export const emailSchema = z.string().email().trim().toLowerCase();

/** Phone validation - accepts international formats */
export const phoneSchema = z.string().regex(/^[\d\s+()-]{7,20}$/, 'Invalid phone number format').optional();

/** Name validation - alphanumeric with spaces, Arabic, and common punctuation */
export const nameSchema = z.string()
  .min(1, 'Name is required')
  .max(100, 'Name is too long')
  .trim();

/** Language preference */
export const languageSchema = z.enum(['ar', 'en']).default('en');

/** UUID/CUID validation */
export const idSchema = z.string().min(1);

/** OTP validation - 6 digit numeric */
export const otpSchema = z.string().length(6).regex(/^\d{6}$/, 'Invalid OTP format');

// =============================================================================
// Contact Form Schema
// =============================================================================

export const contactSubmitSchema = z.object({
  name: nameSchema,
  email: emailSchema,
  phone: phoneSchema,
  company: z.string().max(200).optional(),
  topic: z.enum(['sales', 'support', 'partnership', 'feedback', 'other']).default('other'),
  message: z.string().min(10, 'Message must be at least 10 characters').max(5000, 'Message is too long').trim(),
  preferredLanguage: languageSchema,
  consentGiven: z.literal(true, { errorMap: () => ({ message: 'You must agree to the privacy policy' }) }),
});

export type ContactSubmitInput = z.infer<typeof contactSubmitSchema>;

// =============================================================================
// Auth Schemas
// =============================================================================

export const loginOtpSchema = z.object({
  email: emailSchema,
  language: languageSchema,
});

export type LoginOtpInput = z.infer<typeof loginOtpSchema>;

/** Password validation with strength requirements */
export const passwordSchema = z.string()
  .min(8, 'Password must be at least 8 characters')
  .max(100, 'Password is too long')
  .regex(/[A-Z]/, 'Password must contain at least one uppercase letter')
  .regex(/[a-z]/, 'Password must contain at least one lowercase letter')
  .regex(/[0-9]/, 'Password must contain at least one number');

/** Identifier validation - email or phone */
export const identifierSchema = z.string()
  .min(1, 'Email or phone number is required')
  .trim();

/**
 * Unified login schema - handles all login methods:
 * - Email + OTP (passwordless)
 * - Email + Password
 * - Phone + OTP
 */
export const loginSchema = z.object({
  identifier: identifierSchema,
  password: z.string().optional(),
  useOTP: z.boolean().optional().default(false),
  language: languageSchema,
});

export type LoginInput = z.infer<typeof loginSchema>;

export const verifyOtpSchema = z.object({
  email: emailSchema,
  otp: otpSchema,
});

export type VerifyOtpInput = z.infer<typeof verifyOtpSchema>;

/**
 * Verify Login OTP - supports email, phone, or generic identifier
 */
export const verifyLoginOtpSchema = z.object({
  identifier: identifierSchema.optional(),
  phone: z.string().optional(),
  email: emailSchema.optional(),
  code: otpSchema,
}).refine(
  (data) => data.identifier || data.phone || data.email,
  { message: 'Email, phone, or identifier is required' }
);

export type VerifyLoginOtpInput = z.infer<typeof verifyLoginOtpSchema>;

/**
 * Password reset request schema
 */
export const passwordResetRequestSchema = z.object({
  identifier: identifierSchema,
});

export type PasswordResetRequestInput = z.infer<typeof passwordResetRequestSchema>;

/**
 * Password reset completion schema
 */
export const passwordResetCompleteSchema = z.object({
  identifier: identifierSchema,
  newPassword: passwordSchema,
  resetToken: z.string().min(1, 'Reset token is required'),
});

export type PasswordResetCompleteInput = z.infer<typeof passwordResetCompleteSchema>;

export const forgotPasswordSchema = z.object({
  email: emailSchema,
  language: languageSchema,
});

export type ForgotPasswordInput = z.infer<typeof forgotPasswordSchema>;

export const resetPasswordSchema = z.object({
  email: emailSchema,
  otp: otpSchema,
  newPassword: z.string()
    .min(8, 'Password must be at least 8 characters')
    .max(100, 'Password is too long')
    .regex(/[A-Z]/, 'Password must contain at least one uppercase letter')
    .regex(/[a-z]/, 'Password must contain at least one lowercase letter')
    .regex(/[0-9]/, 'Password must contain at least one number'),
});

export type ResetPasswordInput = z.infer<typeof resetPasswordSchema>;

// =============================================================================
// Signup Schemas
// =============================================================================

export const signupCompanyInfoSchema = z.object({
  companyName: z.string().min(1, 'Company name is required').max(200).trim(),
  industry: z.string().min(1, 'Industry is required'),
  companySize: z.enum(['1-10', '11-50', '51-200', '201-500', '500+']),
  country: z.string().min(1, 'Country is required'),
  city: z.string().optional(),
  website: z.string().url().optional().or(z.literal('')),
});

export type SignupCompanyInfoInput = z.infer<typeof signupCompanyInfoSchema>;

// =============================================================================
// Booking Schemas
// =============================================================================

export const createBookingSchema = z.object({
  customerName: nameSchema,
  customerPhone: z.string().min(7).max(20),
  customerEmail: emailSchema.optional(),
  service: z.string().min(1),
  appointmentDate: z.string().datetime().or(z.coerce.date()),
  appointmentTime: z.string().regex(/^\d{2}:\d{2}$/),
  duration: z.number().min(15).max(480),
  staffMember: z.string().optional(),
  depositAmount: z.number().min(0).optional(),
  totalAmount: z.number().min(0),
  notes: z.string().max(1000).optional(),
  sectorMetadata: z.record(z.string(), z.unknown()).optional(),
  itemType: z.enum(['service', 'product', 'menu_item', 'fee', 'rental']).optional(),
});

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

export const updateBookingStatusSchema = z.object({
  status: z.enum(['pending', 'confirmed', 'cancelled', 'completed', 'no_show']),
  notes: z.string().max(1000).optional(),
});

export type UpdateBookingStatusInput = z.infer<typeof updateBookingStatusSchema>;

/** Schema for creating a booking note */
export const bookingNoteCreateSchema = z.object({
  content: z.string().min(1, 'Note content is required').max(5000, 'Note content cannot exceed 5000 characters').trim(),
});

export type BookingNoteCreateInput = z.infer<typeof bookingNoteCreateSchema>;

/** Schema for updating a booking note */
export const bookingNoteUpdateSchema = z.object({
  content: z.string().min(1, 'Note content is required').max(5000, 'Note content cannot exceed 5000 characters').trim(),
});

export type BookingNoteUpdateInput = z.infer<typeof bookingNoteUpdateSchema>;

/** Schema for marking a booking as paid */
export const markBookingPaidSchema = z.object({
  paymentMethod: z.string().max(50).default('manual'),
  note: z.string().max(500).default(''),
});

export type MarkBookingPaidInput = z.infer<typeof markBookingPaidSchema>;

// =============================================================================
// Organization Schemas
// =============================================================================

export const organizationInvitationSchema = z.object({
  email: emailSchema,
  name: nameSchema.optional(),
  role: z.enum(['ADMIN', 'STAFF']),
});

export type OrganizationInvitationInput = z.infer<typeof organizationInvitationSchema>;

/** Schema for updating a member's role (OWNER only) */
export const updateMemberRoleSchema = z.object({
  targetUserId: z.string().min(1, 'Target user ID is required'),
  newRole: z.enum(['ADMIN', 'STAFF'], { errorMap: () => ({ message: 'Role must be ADMIN or STAFF' }) }),
});

export type UpdateMemberRoleInput = z.infer<typeof updateMemberRoleSchema>;

/** Schema for removing a member from an organization (OWNER only) */
export const removeMemberSchema = z.object({
  targetUserId: z.string().min(1, 'Target user ID is required'),
});

export type RemoveMemberInput = z.infer<typeof removeMemberSchema>;

/** Schema for accepting an invitation */
export const acceptInvitationSchema = z.object({
  token: z.string().min(1, 'Token is required'),
  password: z.string().optional(),
  name: z.string().max(100).trim().optional(),
});

export type AcceptInvitationInput = z.infer<typeof acceptInvitationSchema>;

/** Schema for manually adding seats (admin/recovery) */
export const seatsAddSchema = z.object({
  quantity: z.number().int().min(1, 'Must add at least 1 seat').max(20, 'Cannot add more than 20 seats at once'),
  reason: z.string().max(200).optional(),
});

export type SeatsAddInput = z.infer<typeof seatsAddSchema>;

export const purchaseSeatsSchema = z.object({
  quantity: z.number().int().min(1).max(20, 'Cannot purchase more than 20 seats at once'),
});

export type PurchaseSeatsInput = z.infer<typeof purchaseSeatsSchema>;

// =============================================================================
// Billing Schemas
// =============================================================================

export const planChangeSchema = z.object({
  newTierId: z.enum(['tier1', 'tier2', 'tier3', 'tier4', 'tier5']),
  billingPeriod: z.enum(['monthly', 'yearly']),
  resetTrial: z.boolean().optional(),
});

export type PlanChangeInput = z.infer<typeof planChangeSchema>;

// =============================================================================
// User Profile Schemas
// =============================================================================

export const updateUserProfileSchema = z.object({
  name: nameSchema.optional(),
  companyName: z.string().max(200).optional(),
  industry: z.string().optional(),
  companySize: z.enum(['1-10', '11-50', '51-200', '201-500', '500+']).optional(),
  country: z.string().optional(),
  city: z.string().optional(),
  address: z.string().max(500).optional(),
  phoneNumber: phoneSchema,
  website: z.string().url().optional().or(z.literal('')),
  avatar: z.string().url().optional(),
  timezone: z.string().optional(),
  language: languageSchema.optional(),
});

export type UpdateUserProfileInput = z.infer<typeof updateUserProfileSchema>;

export const changePasswordSchema = z.object({
  currentPassword: z.string().min(1, 'Current password is required'),
  newPassword: z.string()
    .min(8, 'Password must be at least 8 characters')
    .max(100, 'Password is too long')
    .regex(/[A-Z]/, 'Password must contain at least one uppercase letter')
    .regex(/[a-z]/, 'Password must contain at least one lowercase letter')
    .regex(/[0-9]/, 'Password must contain at least one number'),
  confirmPassword: z.string(),
}).refine((data) => data.newPassword === data.confirmPassword, {
  message: 'Passwords do not match',
  path: ['confirmPassword'],
});

export type ChangePasswordInput = z.infer<typeof changePasswordSchema>;

// =============================================================================
// Settings Schemas
// =============================================================================

export const notificationSettingsSchema = z.object({
  emailNotifications: z.boolean(),
  smsNotifications: z.boolean(),
  appointmentReminders: z.boolean(),
  marketingEmails: z.boolean(),
  reminderHours: z.number().min(1).max(72).optional(),
});

export type NotificationSettingsInput = z.infer<typeof notificationSettingsSchema>;

export const businessHoursSchema = z.object({
  dayOfWeek: z.number().min(0).max(6),
  isOpen: z.boolean(),
  openTime: z.string().regex(/^\d{2}:\d{2}$/).optional(),
  closeTime: z.string().regex(/^\d{2}:\d{2}$/).optional(),
});

export type BusinessHoursInput = z.infer<typeof businessHoursSchema>;

export const updateBusinessSettingsSchema = z.object({
  businessName: z.string().max(200).optional(),
  description: z.string().max(1000).optional(),
  address: z.string().max(500).optional(),
  phone: phoneSchema,
  email: emailSchema.optional(),
  website: z.string().url().optional().or(z.literal('')),
  timezone: z.string().optional(),
  currency: z.enum(['QAR', 'SAR', 'AED', 'KWD', 'BHD', 'OMR', 'USD', 'EUR', 'GBP']).optional(),
  businessHours: z.array(businessHoursSchema).optional(),
});

export type UpdateBusinessSettingsInput = z.infer<typeof updateBusinessSettingsSchema>;

// =============================================================================
// Data Export/Delete Schemas (GDPR Compliance)
// =============================================================================

export const exportDataRequestSchema = z.object({
  format: z.enum(['json', 'csv']).default('json'),
  includeBookings: z.boolean().default(true),
  includeConversations: z.boolean().default(true),
  includeBillingHistory: z.boolean().default(true),
});

export type ExportDataRequestInput = z.infer<typeof exportDataRequestSchema>;

export const deleteAccountSchema = z.object({
  confirmation: z.literal('DELETE MY ACCOUNT', {
    errorMap: () => ({ message: 'Please type "DELETE MY ACCOUNT" to confirm' }),
  }),
  password: z.string().min(1, 'Password is required for verification'),
  reason: z.string().max(500).optional(),
});

export type DeleteAccountInput = z.infer<typeof deleteAccountSchema>;

// =============================================================================
// Knowledge Base Schemas
// =============================================================================

export const uploadKnowledgeDocSchema = z.object({
  title: z.string().min(1).max(200),
  content: z.string().optional(),
  fileType: z.enum(['pdf', 'txt', 'doc', 'docx', 'md']).optional(),
  category: z.string().max(100).optional(),
  tags: z.array(z.string().max(50)).max(10).optional(),
});

export type UploadKnowledgeDocInput = z.infer<typeof uploadKnowledgeDocSchema>;

export const queryKnowledgeBaseSchema = z.object({
  query: z.string().min(1).max(1000),
  limit: z.number().min(1).max(20).default(5),
  category: z.string().optional(),
});

export type QueryKnowledgeBaseInput = z.infer<typeof queryKnowledgeBaseSchema>;

// =============================================================================
// Webhook/Integration Schemas
// =============================================================================

export const webhookPayloadSchema = z.object({
  event: z.string().min(1),
  data: z.record(z.unknown()),
  timestamp: z.string().datetime().optional(),
  signature: z.string().optional(),
});

export type WebhookPayloadInput = z.infer<typeof webhookPayloadSchema>;

export const createIntegrationSchema = z.object({
  type: z.enum(['whatsapp', 'google_calendar', 'outlook_calendar', 'n8n', 'zapier']),
  config: z.record(z.unknown()).optional(),
  enabled: z.boolean().default(true),
});

export type CreateIntegrationInput = z.infer<typeof createIntegrationSchema>;

// =============================================================================
// Validation Helper Functions
// =============================================================================

export interface ValidationResult<T> {
  success: true;
  data: T;
}

export interface ValidationError {
  success: false;
  error: string;
  details?: z.ZodError['errors'];
}

/**
 * Validate request body against a Zod schema
 */
export async function validateBody<T extends z.ZodType>(
  request: Request,
  schema: T
): Promise<ValidationResult<z.infer<T>> | ValidationError> {
  try {
    const body = await request.json();
    const result = schema.safeParse(body);

    if (!result.success) {
      return {
        success: false,
        error: result.error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', '),
        details: result.error.errors,
      };
    }

    return {
      success: true,
      data: result.data,
    };
  } catch {
    return {
      success: false,
      error: 'Invalid JSON in request body',
    };
  }
}

/**
 * Validate query parameters against a Zod schema
 */
export function validateQuery<T extends z.ZodType>(
  searchParams: URLSearchParams,
  schema: T
): ValidationResult<z.infer<T>> | ValidationError {
  const params: Record<string, string> = {};
  searchParams.forEach((value, key) => {
    params[key] = value;
  });

  const result = schema.safeParse(params);

  if (!result.success) {
    return {
      success: false,
      error: result.error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', '),
      details: result.error.errors,
    };
  }

  return {
    success: true,
    data: result.data,
  };
}

/**
 * Validate URL parameters against a Zod schema
 */
export function validateParams<T extends z.ZodType>(
  params: Record<string, string | undefined>,
  schema: T
): ValidationResult<z.infer<T>> | ValidationError {
  const result = schema.safeParse(params);

  if (!result.success) {
    return {
      success: false,
      error: result.error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', '),
      details: result.error.errors,
    };
  }

  return {
    success: true,
    data: result.data,
  };
}

// =============================================================================
// Demo Booking Schema
// =============================================================================

/** Valid demo durations */
const demoDurationSchema = z.enum(['15min', '30min', '45min', '60min']);

/** Time format HH:MM (24-hour) */
const timeSchema = z.string().regex(/^([01]\d|2[0-3]):([0-5]\d)$/, 'Invalid time format (use HH:MM)');

/** Date that must be in the future */
const futureDateSchema = z.string().refine(
  (dateStr) => {
    const date = new Date(dateStr);
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    return date >= today;
  },
  { message: 'Date must be in the future' }
);

/** Valid timezones for demo bookings */
const timezoneSchema = z.enum([
  'Asia/Qatar', 'Asia/Dubai', 'Asia/Riyadh', 'Asia/Kuwait',
  'Asia/Bahrain', 'Asia/Muscat', 'Europe/London', 'America/New_York', 'UTC'
]).default('Asia/Qatar');

export const demoBookingSchema = z.object({
  fullName: nameSchema,
  email: emailSchema,
  telephone: z.string().min(7, 'Phone number is required').max(20),
  appointmentDate: futureDateSchema,
  appointmentTime: timeSchema,
  duration: demoDurationSchema,
  specialRequirements: z.string().max(500).optional(),
  language: languageSchema,
  timezone: timezoneSchema.optional(),
  recaptchaToken: z.string().optional(),
  honeypot: z.string().max(0, 'Invalid submission').optional(),
  formStartedAt: z.number().optional(),
  timeOnPageMs: z.number().optional(),
});

export type DemoBookingInput = z.infer<typeof demoBookingSchema>;

/** Schema for confirming a demo booking */
export const demoConfirmSchema = z.object({
  bookingId: z.string().min(1, 'Booking ID is required'),
});

export type DemoConfirmInput = z.infer<typeof demoConfirmSchema>;

/** Schema for demo bookings list query params */
export const demoBookingsQuerySchema = z.object({
  date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Invalid date format. Use YYYY-MM-DD').optional(),
  all: z.enum(['true', 'false']).optional(),
  limit: z.coerce.number().int().min(1).max(500).default(100),
  status: z.enum(['pending', 'confirmed', 'cancelled']).optional(),
});

export type DemoBookingsQueryInput = z.infer<typeof demoBookingsQuerySchema>;

/** Schema for WhatsApp demo tracking webhook */
export const whatsappTrackSchema = z.object({
  event: z.enum(['demo_started', 'demo_completed', 'booking_attempted']),
  phone: z.string().max(20).optional(),
  industry: z.string().max(100).optional(),
  metadata: z.record(z.unknown()).optional(),
});

export type WhatsAppTrackInput = z.infer<typeof whatsappTrackSchema>;

// =============================================================================
// Waitlist Schemas
// =============================================================================

/** Valid waitlist categories */
const waitlistCategorySchema = z.enum(['product', 'feature', 'service', 'event', 'help', 'general']).default('general');

export const createWaitlistSchema = z.object({
  title: z.string().min(1, 'Title is required').max(200).trim(),
  titleAr: z.string().max(200).optional(),
  description: z.string().max(2000).optional(),
  descriptionAr: z.string().max(2000).optional(),
  category: waitlistCategorySchema,
  isActive: z.boolean().default(true),
  isPublic: z.boolean().default(false),
});

export type CreateWaitlistInput = z.infer<typeof createWaitlistSchema>;

export const waitlistSignupSchema = z.object({
  name: nameSchema,
  email: emailSchema,
  mobile: z.string().regex(/^\+?[\d\s()-]{7,20}$/, 'Invalid mobile number').trim(),
  notes: z.string().max(1000).optional(),
});

export type WaitlistSignupInput = z.infer<typeof waitlistSignupSchema>;

// =============================================================================
// Support Ticket Schemas
// =============================================================================

/** Valid ticket categories */
const ticketCategorySchema = z.enum(['BILLING', 'TECHNICAL', 'FEATURE_REQUEST', 'OTHER']);

/** Valid ticket priorities */
const ticketPrioritySchema = z.enum(['LOW', 'NORMAL', 'URGENT']).default('NORMAL');

export const createTicketSchema = z.object({
  subject: z.string().min(3, 'Subject must be at least 3 characters').max(200).trim(),
  category: ticketCategorySchema,
  priority: ticketPrioritySchema.optional(),
  message: z.string().min(10, 'Message must be at least 10 characters').max(10000).trim(),
  attachments: z.array(z.string().url()).max(10).optional(),
});

export type CreateTicketInput = z.infer<typeof createTicketSchema>;

export const ticketMessageSchema = z.object({
  content: z.string().min(1, 'Message cannot be empty').max(10000).trim(),
  attachments: z.array(z.string().url()).max(10).optional(),
});

export type TicketMessageInput = z.infer<typeof ticketMessageSchema>;

// =============================================================================
// Notification Schemas
// =============================================================================

export const markNotificationReadSchema = z.object({
  read: z.boolean(),
});

export type MarkNotificationReadInput = z.infer<typeof markNotificationReadSchema>;

// =============================================================================
// API Key Schemas
// =============================================================================

export const createApiKeySchema = z.object({
  service: z.string().min(2, 'Service name is required (minimum 2 characters)').max(100).trim(),
  keyName: z.string().min(2, 'Key name is required (minimum 2 characters)').max(100).trim(),
  apiKey: z.string().min(10, 'API key is required (minimum 10 characters)').trim(),
  expiresAt: z.string().datetime().optional().or(z.string().optional()),
});

export type CreateApiKeyInput = z.infer<typeof createApiKeySchema>;

// =============================================================================
// Subscription Schemas
// =============================================================================

export const subscriptionUpgradeSchema = z.object({
  planId: z.string().min(1, 'Plan ID is required'),
  billingPeriod: z.enum(['monthly', 'yearly']).optional(),
});

export type SubscriptionUpgradeInput = z.infer<typeof subscriptionUpgradeSchema>;

// =============================================================================
// Checkout Schemas
// =============================================================================

export const checkoutSchema = z.object({
  planId: z.string().min(1, 'Plan is required'),
  billingPeriod: z.enum(['monthly', 'yearly']).default('monthly'),
  successUrl: z.string().url().optional(),
  cancelUrl: z.string().url().optional(),
});

export type CheckoutInput = z.infer<typeof checkoutSchema>;

// =============================================================================
// Sector Metadata Validation
// =============================================================================

/**
 * Validate sector-specific metadata against the configured fields.
 * Checks that all required fields are present.
 * Uses getSectorCustomFields imported at the top of this file.
 */
export function validateSectorMetadata(
  sectorKey: string,
  data: Record<string, unknown> | undefined,
): { valid: boolean; errors: string[] } {
  const fields = getSectorCustomFields(sectorKey);

  // No fields configured — always valid
  if (fields.length === 0) {
    return { valid: true, errors: [] };
  }

  // No data provided — check if any fields are required
  if (!data) {
    const requiredFields = fields.filter((f) => f.required);
    if (requiredFields.length === 0) {
      return { valid: true, errors: [] };
    }
    return {
      valid: false,
      errors: requiredFields.map(
        (f) => `${f.labelEn} is required`,
      ),
    };
  }

  const errors: string[] = [];

  for (const field of fields) {
    const value = data[field.key];
    const isEmpty = value === undefined || value === null || value === '';

    if (field.required && isEmpty) {
      errors.push(`${field.labelEn} is required`);
    }
  }

  return { valid: errors.length === 0, errors };
}
