import { z } from 'zod';
import { supabase } from '@/integrations/supabase/client';

// ============================================
// CENTRALIZED VALIDATION SCHEMAS
// Single source of truth for all entity validation
// ============================================

const currentYear = new Date().getFullYear();

// ============================================
// SHARED IMAGE UPLOAD SCHEMA
// ============================================

const imageAssignmentSchema = z.object({
  uploaded: z.array(z.any()),
  banner_assignment: z.number().int().min(0).nullable().optional(),
  card_assignment: z.number().int().min(0).nullable().optional()
}).optional().default({ uploaded: [], banner_assignment: null, card_assignment: null });

// ============================================
// PARK SCHEMA
// ============================================

export const parkValidationSchema = z.object({
  name: z.string().trim().min(1, 'Park name is required').max(200, 'Name must be less than 200 characters'),
  slug: z.string().trim().min(1, 'Slug is required').regex(/^[a-z0-9-]+$/, 'Slug must contain only lowercase letters, numbers, and hyphens'),
  description: z.string().trim().max(2000, 'Description must be less than 2000 characters').optional().or(z.literal('')),
  park_type: z.string().min(1, 'Park type is required'),
  status: z.enum(['operating', 'closed_permanently', 'closed_temporarily', 'under_construction', 'planned', 'abandoned']),
  opening_date: z.string().optional().or(z.literal('')).refine((val) => {
    if (!val) return true;
    const date = new Date(val);
    return date <= new Date();
  }, 'Opening date cannot be in the future'),
  opening_date_precision: z.enum(['day', 'month', 'year']).optional(),
  closing_date: z.string().optional().or(z.literal('')),
  closing_date_precision: z.enum(['day', 'month', 'year']).optional(),
  location_id: z.string().uuid().optional().nullable(),
  website_url: z.string().trim().optional().or(z.literal('')).refine((val) => {
    if (!val || val === '') return true;
    return z.string().url().safeParse(val).success;
  }, 'Invalid URL format'),
  phone: z.string().trim().max(50, 'Phone must be less than 50 characters').optional().or(z.literal('')),
  email: z.string().trim().optional().or(z.literal('')).refine((val) => {
    if (!val || val === '') return true;
    return z.string().email().safeParse(val).success;
  }, 'Invalid email format'),
  operator_id: z.string()
    .refine(
      val => !val || val === '' || val.startsWith('temp-') || /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(val),
      'Must be a valid UUID or temporary placeholder'
    )
    .optional()
    .nullable()
    .or(z.literal(''))
    .transform(val => val || undefined),
  property_owner_id: z.string()
    .refine(
      val => !val || val === '' || val.startsWith('temp-') || /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(val),
      'Must be a valid UUID or temporary placeholder'
    )
    .optional()
    .nullable()
    .or(z.literal(''))
    .transform(val => val || undefined),
  banner_image_id: z.string().optional(),
  banner_image_url: z.string().optional(),
  card_image_id: z.string().optional(),
  card_image_url: z.string().optional(),
  images: imageAssignmentSchema,
  source_url: z.string().trim().optional().or(z.literal('')).refine((val) => {
    if (!val || val === '') return true;
    return z.string().url().safeParse(val).success;
  }, 'Invalid URL format. Must be a valid URL starting with http:// or https://'),
  submission_notes: z.string().trim()
    .max(1000, 'Submission notes must be less than 1000 characters')
    .optional()
    .or(z.literal('')),
}).refine((data) => {
  if (data.closing_date && data.opening_date) {
    return new Date(data.closing_date) >= new Date(data.opening_date);
  }
  return true;
}, {
  message: 'Closing date must be after opening date',
  path: ['closing_date'],
});

// ============================================
// RIDE SCHEMA
// ============================================

export const rideValidationSchema = z.object({
  name: z.string().trim().min(1, 'Ride name is required').max(200, 'Name must be less than 200 characters'),
  slug: z.string().trim().min(1, 'Slug is required').regex(/^[a-z0-9-]+$/, 'Slug must contain only lowercase letters, numbers, and hyphens'),
  description: z.string().trim().max(2000, 'Description must be less than 2000 characters').optional().or(z.literal('')),
  category: z.string().min(1, 'Category is required'),
  ride_sub_type: z.string().trim().max(100, 'Sub type must be less than 100 characters').optional().or(z.literal('')),
  status: z.enum(['operating', 'closed_permanently', 'closed_temporarily', 'under_construction', 'relocated', 'stored', 'demolished']),
  park_id: z.string().uuid().optional().nullable(),
  designer_id: z.string()
    .refine(
      val => !val || val === '' || val.startsWith('temp-') || /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(val),
      'Must be a valid UUID or temporary placeholder'
    )
    .optional()
    .nullable(),
  opening_date: z.string().optional().or(z.literal('')),
  opening_date_precision: z.enum(['day', 'month', 'year']).optional(),
  closing_date: z.string().optional().or(z.literal('')),
  closing_date_precision: z.enum(['day', 'month', 'year']).optional(),
  height_requirement: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(0, 'Height requirement must be positive').max(300, 'Height requirement must be less than 300cm').optional()
  ),
  age_requirement: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(0, 'Age requirement must be positive').max(100, 'Age requirement must be less than 100').optional()
  ),
  capacity_per_hour: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(1, 'Capacity must be positive').max(99999, 'Capacity must be less than 100,000').optional()
  ),
  duration_seconds: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(1, 'Duration must be positive').max(86400, 'Duration must be less than 24 hours').optional()
  ),
  max_speed_kmh: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().min(0, 'Speed must be positive').max(500, 'Speed must be less than 500 km/h').optional()
  ),
  max_height_meters: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().min(0, 'Height must be positive').max(200, 'Height must be less than 200 meters').optional()
  ),
  length_meters: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().min(0, 'Length must be positive').max(10000, 'Length must be less than 10km').optional()
  ),
  inversions: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(0, 'Inversions must be positive').max(20, 'Inversions must be less than 20').optional()
  ),
  drop_height_meters: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().min(0, 'Drop height must be positive').max(200, 'Drop height must be less than 200 meters').optional()
  ),
  max_g_force: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().min(-10, 'G-force must be greater than -10').max(10, 'G-force must be less than 10').optional()
  ),
  manufacturer_id: z.string()
    .refine(
      val => !val || val === '' || val.startsWith('temp-') || /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(val),
      'Must be a valid UUID or temporary placeholder'
    )
    .optional()
    .nullable(),
  ride_model_id: z.string()
    .refine(
      val => !val || val === '' || val.startsWith('temp-') || /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(val),
      'Must be a valid UUID or temporary placeholder'
    )
    .optional()
    .nullable(),
  coaster_type: z.string().optional(),
  seating_type: z.string().optional(),
  intensity_level: z.string().optional(),
  track_material: z.array(z.string()).optional().nullable(),
  support_material: z.array(z.string()).optional().nullable(),
  propulsion_method: z.array(z.string()).optional().nullable(),
  // Water ride specific fields
  water_depth_cm: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().min(0, 'Water depth must be positive').max(1000, 'Water depth must be less than 1000cm').optional()
  ),
  splash_height_meters: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().min(0, 'Splash height must be positive').max(100, 'Splash height must be less than 100 meters').optional()
  ),
  wetness_level: z.enum(['dry', 'light', 'moderate', 'soaked']).optional(),
  flume_type: z.string().trim().max(100, 'Flume type must be less than 100 characters').optional().or(z.literal('')),
  boat_capacity: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(1, 'Boat capacity must be positive').max(100, 'Boat capacity must be less than 100').optional()
  ),
  // Dark ride specific fields
  theme_name: z.string().trim().max(200, 'Theme name must be less than 200 characters').optional().or(z.literal('')),
  story_description: z.string().trim().max(2000, 'Story description must be less than 2000 characters').optional().or(z.literal('')),
  show_duration_seconds: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(0, 'Show duration must be positive').max(7200, 'Show duration must be less than 2 hours').optional()
  ),
  animatronics_count: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(0, 'Animatronics count must be positive').max(1000, 'Animatronics count must be less than 1000').optional()
  ),
  projection_type: z.string().trim().max(100, 'Projection type must be less than 100 characters').optional().or(z.literal('')),
  ride_system: z.string().trim().max(100, 'Ride system must be less than 100 characters').optional().or(z.literal('')),
  scenes_count: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(0, 'Scenes count must be positive').max(100, 'Scenes count must be less than 100').optional()
  ),
  // Flat ride specific fields
  rotation_type: z.enum(['horizontal', 'vertical', 'multi_axis', 'pendulum', 'none']).optional(),
  motion_pattern: z.string().trim().max(200, 'Motion pattern must be less than 200 characters').optional().or(z.literal('')),
  platform_count: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(1, 'Platform count must be positive').max(100, 'Platform count must be less than 100').optional()
  ),
  swing_angle_degrees: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().min(0, 'Swing angle must be positive').max(360, 'Swing angle must be less than 360 degrees').optional()
  ),
  rotation_speed_rpm: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().min(0, 'Rotation speed must be positive').max(200, 'Rotation speed must be less than 200 RPM').optional()
  ),
  arm_length_meters: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().min(0, 'Arm length must be positive').max(100, 'Arm length must be less than 100 meters').optional()
  ),
  max_height_reached_meters: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().min(0, 'Max height reached must be positive').max(200, 'Max height reached must be less than 200 meters').optional()
  ),
  // Kiddie ride specific fields
  min_age: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(0, 'Min age must be positive').max(18, 'Min age must be less than 18').optional()
  ),
  max_age: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(0, 'Max age must be positive').max(18, 'Max age must be less than 18').optional()
  ),
  educational_theme: z.string().trim().max(200, 'Educational theme must be less than 200 characters').optional().or(z.literal('')),
  character_theme: z.string().trim().max(200, 'Character theme must be less than 200 characters').optional().or(z.literal('')),
  // Transportation ride specific fields
  transport_type: z.enum(['train', 'monorail', 'skylift', 'ferry', 'peoplemover', 'cable_car']).optional(),
  route_length_meters: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().min(0, 'Route length must be positive').max(50000, 'Route length must be less than 50km').optional()
  ),
  stations_count: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(2, 'Stations count must be at least 2').max(50, 'Stations count must be less than 50').optional()
  ),
  vehicle_capacity: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(1, 'Vehicle capacity must be positive').max(500, 'Vehicle capacity must be less than 500').optional()
  ),
  vehicles_count: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(1, 'Vehicles count must be positive').max(100, 'Vehicles count must be less than 100').optional()
  ),
  round_trip_duration_seconds: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(0, 'Round trip duration must be positive').max(7200, 'Round trip duration must be less than 2 hours').optional()
  ),
  banner_image_id: z.string().optional(),
  banner_image_url: z.string().optional(),
  card_image_id: z.string().optional(),
  card_image_url: z.string().optional(),
  images: imageAssignmentSchema,
  source_url: z.string().trim().optional().or(z.literal('')).refine((val) => {
    if (!val || val === '') return true;
    return z.string().url().safeParse(val).success;
  }, 'Invalid URL format. Must be a valid URL starting with http:// or https://'),
  submission_notes: z.string().trim()
    .max(1000, 'Submission notes must be less than 1000 characters')
    .optional()
    .or(z.literal('')),
});

// ============================================
// COMPANY SCHEMA (Manufacturer, Designer, Operator, Property Owner)
// ============================================

export const companyValidationSchema = z.object({
  name: z.string().trim().min(1, 'Company name is required').max(200, 'Name must be less than 200 characters'),
  slug: z.string().trim().min(1, 'Slug is required').regex(/^[a-z0-9-]+$/, 'Slug must contain only lowercase letters, numbers, and hyphens'),
  company_type: z.enum(['manufacturer', 'designer', 'operator', 'property_owner']),
  description: z.string().trim().max(2000, 'Description must be less than 2000 characters').optional().or(z.literal('')),
  person_type: z.enum(['company', 'individual', 'firm', 'organization']),
  founded_date: z.string().optional().or(z.literal('')),
  founded_date_precision: z.enum(['day', 'month', 'year']).optional(),
  founded_year: z.preprocess(
    (val) => val === '' || val === null || val === undefined ? undefined : Number(val),
    z.number().int().min(1800, 'Founded year must be after 1800').max(currentYear, `Founded year cannot be after ${currentYear}`).optional()
  ),
  headquarters_location: z.string().trim().max(200, 'Location must be less than 200 characters').optional().or(z.literal('')),
  website_url: z.string().trim().optional().or(z.literal('')).refine((val) => {
    if (!val || val === '') return true;
    return z.string().url().safeParse(val).success;
  }, 'Invalid URL format'),
  banner_image_id: z.string().optional(),
  banner_image_url: z.string().optional(),
  card_image_id: z.string().optional(),
  card_image_url: z.string().optional(),
  images: imageAssignmentSchema,
  source_url: z.string().trim().optional().or(z.literal('')).refine((val) => {
    if (!val || val === '') return true;
    return z.string().url().safeParse(val).success;
  }, 'Invalid URL format. Must be a valid URL starting with http:// or https://'),
  submission_notes: z.string().trim()
    .max(1000, 'Submission notes must be less than 1000 characters')
    .optional()
    .or(z.literal('')),
});

// ============================================
// RIDE MODEL SCHEMA
// ============================================

export const rideModelValidationSchema = z.object({
  name: z.string().trim().min(1, 'Model name is required').max(200, 'Name must be less than 200 characters'),
  slug: z.string().trim().min(1, 'Slug is required').regex(/^[a-z0-9-]+$/, 'Slug must contain only lowercase letters, numbers, and hyphens'),
  category: z.string().min(1, 'Category is required'),
  ride_type: z.string().trim().min(1, 'Ride type is required').max(100, 'Ride type must be less than 100 characters'),
  description: z.string().trim().max(2000, 'Description must be less than 2000 characters').optional().or(z.literal('')),
  manufacturer_id: z.string()
    .refine(
      val => !val || val === '' || val.startsWith('temp-') || /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(val),
      'Must be a valid UUID or temporary placeholder'
    )
    .optional(),
  source_url: z.string().trim().optional().or(z.literal('')).refine((val) => {
    if (!val || val === '') return true;
    return z.string().url().safeParse(val).success;
  }, 'Invalid URL format. Must be a valid URL starting with http:// or https://'),
  submission_notes: z.string().trim()
    .max(1000, 'Submission notes must be less than 1000 characters')
    .optional()
    .or(z.literal('')),
});

// ============================================
// PHOTO SCHEMA
// ============================================

export const photoValidationSchema = z.object({
  cloudflare_image_id: z.string().min(1, 'Image ID is required'),
  cloudflare_image_url: z.string().url('Invalid image URL'),
  entity_type: z.string().min(1, 'Entity type is required'),
  entity_id: z.string().uuid('Invalid entity ID'),
  caption: z.string().trim().max(500, 'Caption must be less than 500 characters').optional().or(z.literal('')),
  photographer_credit: z.string().trim().max(200, 'Credit must be less than 200 characters').optional().or(z.literal('')),
});

// ============================================
// MILESTONE/TIMELINE EVENT SCHEMA
// ============================================

export const milestoneValidationSchema = z.object({
  title: z.string().trim().min(1, 'Event title is required').max(200, 'Title must be less than 200 characters'),
  description: z.string().trim().max(2000, 'Description must be less than 2000 characters').optional().or(z.literal('')),
  event_type: z.string().min(1, 'Event type is required'),
  event_date: z.string().min(1, 'Event date is required').refine((val) => {
    if (!val) return true;
    const date = new Date(val);
    const fiveYearsFromNow = new Date();
    fiveYearsFromNow.setFullYear(fiveYearsFromNow.getFullYear() + 5);
    return date <= fiveYearsFromNow;
  }, 'Event date cannot be more than 5 years in the future'),
  event_date_precision: z.enum(['day', 'month', 'year']).optional().default('day'),
  entity_type: z.string().min(1, 'Entity type is required'),
  entity_id: z.string().uuid('Invalid entity ID'),
  is_public: z.boolean().optional(),
  display_order: z.number().optional(),
  from_value: z.string().trim().max(200).optional().or(z.literal('')),
  to_value: z.string().trim().max(200).optional().or(z.literal('')),
  from_entity_id: z.string().uuid().optional().nullable(),
  to_entity_id: z.string().uuid().optional().nullable(),
  from_location_id: z.string().uuid().optional().nullable(),
  to_location_id: z.string().uuid().optional().nullable(),
}).refine((data) => {
  // For change events, require from_value or to_value
  const changeEvents = ['name_change', 'operator_change', 'owner_change', 'location_change', 'status_change'];
  if (changeEvents.includes(data.event_type)) {
    return data.from_value || data.to_value || data.from_entity_id || data.to_entity_id || data.from_location_id || data.to_location_id;
  }
  return true;
}, {
  message: 'Change events must specify what changed (from/to values or entity IDs)',
  path: ['from_value'],
});

// ============================================
// PHOTO OPERATION SCHEMAS
// ============================================

export const photoEditValidationSchema = z.object({
  photo_id: z.string().uuid('Invalid photo ID'),
  cloudflare_image_url: z.string().url('Invalid image URL'),
  caption: z.string().trim().max(500, 'Caption must be less than 500 characters').optional().or(z.literal('')),
  title: z.string().trim().max(200, 'Title must be less than 200 characters').optional().or(z.literal('')),
  entity_type: z.string().min(1, 'Entity type is required'),
  entity_id: z.string().uuid('Invalid entity ID'),
});

export const photoDeleteValidationSchema = z.object({
  photo_id: z.string().uuid('Invalid photo ID'),
  cloudflare_image_id: z.string().min(1, 'Image ID is required'),
  cloudflare_image_url: z.string().url('Invalid image URL').optional(),
  entity_type: z.string().min(1, 'Entity type is required'),
  entity_id: z.string().uuid('Invalid entity ID'),
});

// ============================================
// SCHEMA REGISTRY
// ============================================

export const entitySchemas = {
  park: parkValidationSchema,
  ride: rideValidationSchema,
  manufacturer: companyValidationSchema,
  designer: companyValidationSchema,
  operator: companyValidationSchema,
  property_owner: companyValidationSchema,
  ride_model: rideModelValidationSchema,
  photo: photoValidationSchema,
  photo_edit: photoEditValidationSchema,
  photo_delete: photoDeleteValidationSchema,
  milestone: milestoneValidationSchema,
  timeline_event: milestoneValidationSchema, // Alias for milestone
};

// ============================================
// VALIDATION RESULT TYPES
// ============================================

export interface ValidationError {
  field: string;
  message: string;
  severity: 'blocking' | 'warning' | 'suggestion';
}

export interface ValidationResult {
  isValid: boolean;
  blockingErrors: ValidationError[];
  warnings: ValidationError[];
  suggestions: ValidationError[];
  allErrors: ValidationError[];
}

// ============================================
// VALIDATION HELPERS
// ============================================

/**
 * Validate entity data against its schema
 * Returns detailed validation result with errors categorized by severity
 */
export async function validateEntityData(
  entityType: keyof typeof entitySchemas,
  data: unknown
): Promise<ValidationResult> {
  const schema = entitySchemas[entityType];
  
  if (!schema) {
    return {
      isValid: false,
      blockingErrors: [{ field: 'entity_type', message: `Unknown entity type: ${entityType}`, severity: 'blocking' }],
      warnings: [],
      suggestions: [],
      allErrors: [{ field: 'entity_type', message: `Unknown entity type: ${entityType}`, severity: 'blocking' }],
    };
  }

  const result = schema.safeParse(data);
  const blockingErrors: ValidationError[] = [];
  const warnings: ValidationError[] = [];
  const suggestions: ValidationError[] = [];

  // Process Zod errors
  if (!result.success) {
    const zodError = result.error as z.ZodError;
    zodError.issues.forEach((issue) => {
      const field = issue.path.join('.');
      blockingErrors.push({
        field: field || 'unknown',
        message: issue.message,
        severity: 'blocking',
      });
    });
  }

  // Add warnings for optional but recommended fields
  const validData = data as Record<string, unknown>;
  if (validData.description && typeof validData.description === 'string' && validData.description.length < 50) {
    warnings.push({
      field: 'description',
      message: 'Description is short. Recommended: 50+ characters',
      severity: 'warning',
    });
  }

  if (entityType === 'park' || entityType === 'ride') {
    if (!validData.description || (typeof validData.description === 'string' && validData.description.trim() === '')) {
      warnings.push({
        field: 'description',
        message: 'No description provided. Adding a description improves content quality',
        severity: 'warning',
      });
    }
  }

  // Check slug uniqueness (async) - only if slug has changed
  if (validData.slug && typeof validData.slug === 'string') {
    // Extract the correct ID field based on entity type
    let entityId: string | undefined;
    
    switch (entityType) {
      case 'park':
        entityId = typeof validData.park_id === 'string' ? validData.park_id : undefined;
        break;
      case 'ride':
        entityId = typeof validData.ride_id === 'string' ? validData.ride_id : undefined;
        break;
      case 'manufacturer':
      case 'designer':
      case 'operator':
      case 'property_owner':
        entityId = typeof validData.company_id === 'string' 
          ? validData.company_id 
          : (typeof validData.id === 'string' ? validData.id : undefined);
        break;
      case 'ride_model':
        entityId = typeof validData.ride_model_id === 'string' 
          ? validData.ride_model_id 
          : (typeof validData.id === 'string' ? validData.id : undefined);
        break;
      default:
        entityId = typeof validData.id === 'string' ? validData.id : undefined;
    }
    
    // If we have an entity ID, check if slug has actually changed
    let shouldCheckUniqueness = true;
    if (entityId) {
      const tableName = getTableNameFromEntityType(entityType);
      
      // Use switch to avoid TypeScript type instantiation issues
      let originalSlug: string | null = null;
      switch (tableName) {
        case 'parks': {
          const { data } = await supabase.from('parks').select('slug').eq('id', entityId).single();
          originalSlug = data?.slug || null;
          break;
        }
        case 'rides': {
          const { data } = await supabase.from('rides').select('slug').eq('id', entityId).single();
          originalSlug = data?.slug || null;
          break;
        }
        case 'companies': {
          const { data } = await supabase.from('companies').select('slug').eq('id', entityId).single();
          originalSlug = data?.slug || null;
          break;
        }
        case 'ride_models': {
          const { data } = await supabase.from('ride_models').select('slug').eq('id', entityId).single();
          originalSlug = data?.slug || null;
          break;
        }
      }
      
      // If slug hasn't changed, skip uniqueness check
      if (originalSlug && originalSlug === validData.slug) {
        shouldCheckUniqueness = false;
      }
    }
    
    // Only check uniqueness if this is a new entity or slug has changed
    if (shouldCheckUniqueness) {
      const isSlugUnique = await checkSlugUniqueness(
        entityType, 
        validData.slug, 
        entityId
      );
      
      if (!isSlugUnique) {
        blockingErrors.push({
          field: 'slug',
          message: 'This slug is already in use. Manually check if this entity already exists, and reject if so. Otherwise, escalate to an admin for manual editing of the slug.',
          severity: 'blocking',
        });
      }
    }
  }

  const allErrors = [...blockingErrors, ...warnings, ...suggestions];
  const isValid = blockingErrors.length === 0;

  return {
    isValid,
    blockingErrors,
    warnings,
    suggestions,
    allErrors,
  };
}

/**
 * Check if slug is unique for the entity type
 */
async function checkSlugUniqueness(
  entityType: keyof typeof entitySchemas,
  slug: string,
  excludeId?: string
): Promise<boolean> {
  const tableName = getTableNameFromEntityType(entityType);
  
  try {
    // Query with explicit table name - use simple approach to avoid type instantiation issues
    let result;
    
    switch (tableName) {
      case 'parks':
        result = await supabase.from('parks').select('id').eq('slug', slug).limit(1);
        break;
      case 'rides':
        result = await supabase.from('rides').select('id').eq('slug', slug).limit(1);
        break;
      case 'companies':
        result = await supabase.from('companies').select('id').eq('slug', slug).limit(1);
        break;
      case 'ride_models':
        result = await supabase.from('ride_models').select('id').eq('slug', slug).limit(1);
        break;
      default:
        return true; // Assume unique on invalid table
    }

    const { data, error } = result;

    if (error) {
      return true; // Assume unique on error to avoid blocking
    }

    // If no data, slug is unique
    if (!data || data.length === 0) {
      return true;
    }

    // If excludeId provided and matches, it's the same entity (editing)
    if (excludeId && data[0] && data[0].id === excludeId) {
      return true;
    }

    // Slug is in use by a different entity
    return false;
  } catch (error) {
    return true; // Assume unique on error to avoid false positives
  }
}

/**
 * Get database table name from entity type
 */
function getTableNameFromEntityType(entityType: keyof typeof entitySchemas): string {
  switch (entityType) {
    case 'park':
      return 'parks';
    case 'ride':
      return 'rides';
    case 'manufacturer':
    case 'designer':
    case 'operator':
    case 'property_owner':
      return 'companies';
    case 'ride_model':
      return 'ride_models';
    case 'photo':
      return 'photos';
    default:
      return entityType + 's';
  }
}

/**
 * Batch validate multiple items
 */
export async function validateMultipleItems(
  items: Array<{ item_type: string; item_data: unknown; id?: string }>
): Promise<Map<string, ValidationResult>> {
  const results = new Map<string, ValidationResult>();

  await Promise.all(
    items.map(async (item) => {
      const result = await validateEntityData(
        item.item_type as keyof typeof entitySchemas,
        { ...(item.item_data as object), id: item.id }
      );
      const validData = item.item_data as Record<string, unknown>;
      results.set(
        item.id || (typeof validData.slug === 'string' ? validData.slug : ''), 
        result
      );
    })
  );

  return results;
}
