import type { AppliedDataSemantic } from '../Semantics.js'
import { SemanticType } from '../Semantics.js'

/**
 * Supported SKU validation modes.
 */
export type SKUValidationMode = 'strict' | 'lenient' | 'custom'

/**
 * Supported SKU case transformation modes.
 */
export type SKUCaseMode = 'uppercase' | 'lowercase' | 'preserve'

/**
 * Configuration options for the SKU semantic.
 * Controls SKU validation, formatting, uniqueness enforcement, and pattern matching.
 */
export interface SKUConfig {
  /**
   * The validation mode for SKU format.
   *
   * - 'strict': Enforces alphanumeric characters with optional hyphens/underscores
   * - 'lenient': Allows more special characters but still validates basic format
   * - 'custom': Uses custom regex pattern defined in `customPattern`
   */
  validationMode?: SKUValidationMode

  /**
   * Custom regex pattern for SKU validation when using 'custom' validation mode.
   * Only used when validationMode is 'custom'.
   */
  customPattern?: string

  /**
   * Case transformation to apply to SKUs.
   * - 'uppercase': Convert to uppercase (recommended for consistency)
   * - 'lowercase': Convert to lowercase
   * - 'preserve': Keep original case
   */
  caseMode?: SKUCaseMode

  /**
   * Prefix to automatically add to SKUs if not present.
   * Useful for organizing SKUs by category (e.g., 'PROD-', 'SKU-').
   */
  prefix?: string

  /**
   * Whether to enforce global uniqueness across all entities.
   * When true, creates unique database constraints.
   * Default: true
   */
  enforceUniqueness?: boolean

  /**
   * Whether to auto-generate SKUs when not provided.
   * When true, generates SKUs based on other fields or random values.
   * Default: false
   */
  autoGenerate?: boolean

  /**
   * Field key to use as source for auto-generation.
   * Only used when autoGenerate is true.
   * If not specified, uses random generation.
   *
   * The kay can be any field that provides a meaningful value for the SKU. It can also be a key of
   * a property in one of the parent entities.
   */
  autoGenerateSource?: string

  /**
   * Whether to validate that SKU doesn't conflict with reserved words or patterns.
   * Default: true
   */
  validateReservedWords?: boolean

  /**
   * List of reserved SKU values that cannot be used.
   * Common examples: 'ADMIN', 'TEST', 'NULL', 'DEFAULT'
   */
  reservedValues?: string[]

  /**
   * Custom metadata for the SKU field.
   */
  metadata?: Record<string, unknown>

  /**
   * Index signature to allow additional properties.
   */
  [key: string]: unknown
}

/**
 * Type-safe configuration for SKU semantic.
 */
export interface AppliedSKUSemantic extends AppliedDataSemantic {
  id: SemanticType.SKU
  config?: SKUConfig
}

/**
 * Type guard to check if a semantic is a SKU semantic.
 */
export const isSKUSemantic = (semantic: AppliedDataSemantic): semantic is AppliedSKUSemantic => {
  return semantic.id === SemanticType.SKU
}

/**
 * Helper function to create a SKU semantic with configuration.
 */
export const createSKUSemantic = (config: SKUConfig = {}): AppliedSKUSemantic => {
  const mergedConfig = {
    ...DEFAULT_SKU_CONFIG,
    ...config,
  }

  // Merge metadata separately
  if (config.metadata) {
    mergedConfig.metadata = { ...config.metadata }
  }

  return {
    id: SemanticType.SKU,
    config: mergedConfig,
  }
}

/**
 * Default configuration for SKU semantic.
 * Optimized for common product catalog use cases.
 */
export const DEFAULT_SKU_CONFIG: SKUConfig = {
  validationMode: 'strict',
  caseMode: 'uppercase',
  enforceUniqueness: true,
  autoGenerate: false,
  validateReservedWords: true,
  reservedValues: ['ADMIN', 'TEST', 'NULL', 'DEFAULT', 'UNDEFINED', 'SAMPLE', 'DEMO'],
}

/**
 * Predefined configurations for common use cases.
 */
export const SKU_PRESETS = {
  /**
   * Standard product SKU with strict validation and uppercase formatting.
   */
  PRODUCT_STANDARD: createSKUSemantic({
    validationMode: 'strict',
    caseMode: 'uppercase',
    prefix: 'PROD-',
    enforceUniqueness: true,
    validateReservedWords: true,
    reservedValues: ['ADMIN', 'TEST', 'NULL', 'DEFAULT'],
  }),

  /**
   * Simple SKU configuration for basic catalogs.
   */
  SIMPLE: createSKUSemantic({
    validationMode: 'lenient',
    caseMode: 'preserve',
    enforceUniqueness: true,
  }),

  /**
   * Auto-generating SKU from product name.
   */
  AUTO_GENERATE: createSKUSemantic({
    validationMode: 'strict',
    caseMode: 'uppercase',
    autoGenerate: true,
    autoGenerateSource: 'name',
    enforceUniqueness: true,
  }),

  /**
   * Flexible SKU for variable product types.
   */
  FLEXIBLE: createSKUSemantic({
    validationMode: 'lenient',
    caseMode: 'preserve',
    enforceUniqueness: true,
    validateReservedWords: false,
  }),
} as const

/**
 * Helper function to validate a SKU configuration.
 */
export const validateSKUConfig = (config: SKUConfig): string[] => {
  const errors: string[] = []

  if (config.validationMode === 'custom' && !config.customPattern) {
    errors.push('customPattern is required when validationMode is custom')
  }

  if (config.customPattern) {
    try {
      new RegExp(config.customPattern)
    } catch {
      errors.push('customPattern must be a valid regular expression')
    }
  }

  if (config.prefix && config.prefix.length === 0) {
    errors.push('prefix cannot be empty string')
  }

  if (config.autoGenerateSource && !config.autoGenerate) {
    errors.push('autoGenerate must be true when autoGenerateSource is specified')
  }

  return errors
}

/**
 * Helper function to validate SKU value against configuration.
 */
export const validateSKUValue = (value: string, config: SKUConfig = DEFAULT_SKU_CONFIG): string[] => {
  const errors: string[] = []
  const mergedConfig = { ...DEFAULT_SKU_CONFIG, ...config }

  if (!value || typeof value !== 'string') {
    errors.push('SKU value must be a non-empty string')
    return errors
  }

  if (mergedConfig.validateReservedWords && mergedConfig.reservedValues) {
    const normalizedValue = value.toUpperCase()
    if (mergedConfig.reservedValues.some((reserved) => reserved.toUpperCase() === normalizedValue)) {
      errors.push(`SKU cannot use reserved value: ${value}`)
    }
  }

  // Validation pattern checks
  if (mergedConfig.validationMode === 'strict') {
    if (!/^[A-Za-z0-9_-]+$/.test(value)) {
      errors.push('SKU can only contain alphanumeric characters, hyphens, and underscores')
    }
  } else if (mergedConfig.validationMode === 'lenient') {
    if (!/^[A-Za-z0-9_.-]+$/.test(value)) {
      errors.push('SKU contains invalid characters')
    }
  } else if (mergedConfig.validationMode === 'custom' && mergedConfig.customPattern) {
    try {
      const regex = new RegExp(mergedConfig.customPattern)
      if (!regex.test(value)) {
        errors.push('SKU does not match the required pattern')
      }
    } catch {
      errors.push('Invalid custom pattern configuration')
    }
  }

  return errors
}
