import { test } from '@japa/runner'
import {
  createSKUSemantic,
  isSKUSemantic,
  type SKUConfig,
  DEFAULT_SKU_CONFIG,
  SKU_PRESETS,
  validateSKUConfig,
  validateSKUValue,
} from '../../../../src/modeling/definitions/SKU.js'
import { SemanticType, type AppliedDataSemantic } from '../../../../src/modeling/Semantics.js'

test.group('SKU Semantic Configuration', () => {
  test('should create semantic with default config', ({ assert }) => {
    const semantic = createSKUSemantic()
    assert.equal(semantic.id, SemanticType.SKU)
    assert.deepEqual(semantic.config, DEFAULT_SKU_CONFIG)
  })

  test('should create semantic with custom config', ({ assert }) => {
    const config: SKUConfig = {
      validationMode: 'lenient',
      caseMode: 'lowercase',
      prefix: 'PROD-',
      enforceUniqueness: false,
    }
    const semantic = createSKUSemantic(config)
    assert.equal(semantic.id, SemanticType.SKU)
    assert.deepEqual(semantic.config, { ...DEFAULT_SKU_CONFIG, ...config })
  })

  test('should merge metadata separately', ({ assert }) => {
    const config: SKUConfig = {
      metadata: { source: 'legacy-system' },
    }
    const semantic = createSKUSemantic(config)
    assert.deepEqual(semantic.config?.metadata, { source: 'legacy-system' })
  })

  test('should identify SKU semantic', ({ assert }) => {
    const semantic = createSKUSemantic()
    assert.isTrue(isSKUSemantic(semantic))
  })

  test('should not identify non-SKU semantic', ({ assert }) => {
    const fakeSemantic: AppliedDataSemantic = { id: SemanticType.Email, config: {} }
    assert.isFalse(isSKUSemantic(fakeSemantic))
  })

  test('presets should be valid SKU semantics', ({ assert }) => {
    Object.values(SKU_PRESETS).forEach((preset) => {
      assert.isTrue(isSKUSemantic(preset))
      assert.equal(preset.id, SemanticType.SKU)
    })
  })

  test('PRODUCT_STANDARD preset should have correct configuration', ({ assert }) => {
    const preset = SKU_PRESETS.PRODUCT_STANDARD
    assert.equal(preset.config?.validationMode, 'strict')
    assert.equal(preset.config?.caseMode, 'uppercase')
    assert.equal(preset.config?.prefix, 'PROD-')
    assert.equal(preset.config?.enforceUniqueness, true)
  })

  test('SIMPLE preset should have correct configuration', ({ assert }) => {
    const preset = SKU_PRESETS.SIMPLE
    assert.equal(preset.config?.validationMode, 'lenient')
    assert.equal(preset.config?.caseMode, 'preserve')
    assert.equal(preset.config?.enforceUniqueness, true)
  })

  test('AUTO_GENERATE preset should have correct configuration', ({ assert }) => {
    const preset = SKU_PRESETS.AUTO_GENERATE
    assert.equal(preset.config?.validationMode, 'strict')
    assert.equal(preset.config?.caseMode, 'uppercase')
    assert.equal(preset.config?.autoGenerate, true)
    assert.equal(preset.config?.autoGenerateSource, 'name')
    assert.equal(preset.config?.enforceUniqueness, true)
  })

  test('FLEXIBLE preset should have correct configuration', ({ assert }) => {
    const preset = SKU_PRESETS.FLEXIBLE
    assert.equal(preset.config?.validationMode, 'lenient')
    assert.equal(preset.config?.caseMode, 'preserve')
    assert.equal(preset.config?.enforceUniqueness, true)
    assert.equal(preset.config?.validateReservedWords, false)
  })
})

test.group('SKU Configuration Validation', () => {
  test('should validate valid configuration', ({ assert }) => {
    const config: SKUConfig = {
      validationMode: 'strict',
      caseMode: 'uppercase',
    }
    const errors = validateSKUConfig(config)
    assert.lengthOf(errors, 0)
  })

  test('should require customPattern when validationMode is custom', ({ assert }) => {
    const config: SKUConfig = { validationMode: 'custom' }
    const errors = validateSKUConfig(config)
    assert.include(errors, 'customPattern is required when validationMode is custom')
  })

  test('should validate custom pattern regex', ({ assert }) => {
    const config: SKUConfig = { validationMode: 'custom', customPattern: '[invalid regex' }
    const errors = validateSKUConfig(config)
    assert.include(errors, 'customPattern must be a valid regular expression')
  })

  test('should require autoGenerate when autoGenerateSource is specified', ({ assert }) => {
    const config: SKUConfig = { autoGenerateSource: 'name', autoGenerate: false }
    const errors = validateSKUConfig(config)
    assert.include(errors, 'autoGenerate must be true when autoGenerateSource is specified')
  })

  test('should accept valid custom pattern', ({ assert }) => {
    const config: SKUConfig = { validationMode: 'custom', customPattern: '^[A-Z]{3}-\\d{3}$' }
    const errors = validateSKUConfig(config)
    assert.lengthOf(errors, 0)
  })
})

test.group('SKU Value Validation', () => {
  test('should validate valid SKU with default config', ({ assert }) => {
    const errors = validateSKUValue('PRODUCT123')
    assert.lengthOf(errors, 0)
  })

  test('should reject empty or null values', ({ assert }) => {
    assert.include(validateSKUValue(''), 'SKU value must be a non-empty string')
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    assert.include(validateSKUValue(null as any), 'SKU value must be a non-empty string')
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    assert.include(validateSKUValue(undefined as any), 'SKU value must be a non-empty string')
  })

  test('should validate strict mode', ({ assert }) => {
    const config: SKUConfig = { validationMode: 'strict' }

    assert.lengthOf(validateSKUValue('ABC123', config), 0)
    assert.lengthOf(validateSKUValue('ABC-123', config), 0)
    assert.lengthOf(validateSKUValue('ABC_123', config), 0)
    assert.include(
      validateSKUValue('ABC.123', config),
      'SKU can only contain alphanumeric characters, hyphens, and underscores'
    )
    assert.include(
      validateSKUValue('ABC@123', config),
      'SKU can only contain alphanumeric characters, hyphens, and underscores'
    )
  })

  test('should validate lenient mode', ({ assert }) => {
    const config: SKUConfig = { validationMode: 'lenient' }

    assert.lengthOf(validateSKUValue('ABC123', config), 0)
    assert.lengthOf(validateSKUValue('ABC-123', config), 0)
    assert.lengthOf(validateSKUValue('ABC_123', config), 0)
    assert.lengthOf(validateSKUValue('ABC.123', config), 0)
    assert.include(validateSKUValue('ABC@123', config), 'SKU contains invalid characters')
    assert.include(validateSKUValue('ABC#123', config), 'SKU contains invalid characters')
  })

  test('should validate custom pattern mode', ({ assert }) => {
    const config: SKUConfig = {
      validationMode: 'custom',
      customPattern: '^[A-Z]{3}-\\d{3}$',
    }

    assert.lengthOf(validateSKUValue('ABC-123', config), 0)
    assert.include(validateSKUValue('abc-123', config), 'SKU does not match the required pattern')
    assert.include(validateSKUValue('ABCD-123', config), 'SKU does not match the required pattern')
    assert.include(validateSKUValue('ABC-12', config), 'SKU does not match the required pattern')
  })

  test('should validate reserved words', ({ assert }) => {
    const config: SKUConfig = {
      validateReservedWords: true,
      reservedValues: ['ADMIN', 'TEST', 'NULL'],
    }

    assert.include(validateSKUValue('ADMIN', config), 'SKU cannot use reserved value: ADMIN')
    assert.include(validateSKUValue('test', config), 'SKU cannot use reserved value: test')
    assert.include(validateSKUValue('null', config), 'SKU cannot use reserved value: null')
    assert.lengthOf(validateSKUValue('PRODUCT', config), 0)
  })

  test('should skip reserved word validation when disabled', ({ assert }) => {
    const config: SKUConfig = {
      validateReservedWords: false,
      reservedValues: ['ADMIN', 'TEST'],
    }

    assert.lengthOf(validateSKUValue('ADMIN', config), 0)
    assert.lengthOf(validateSKUValue('TEST', config), 0)
  })

  test('should handle invalid custom pattern gracefully', ({ assert }) => {
    const config: SKUConfig = {
      validationMode: 'custom',
      customPattern: '[invalid',
    }

    assert.include(validateSKUValue('ANYTHING', config), 'Invalid custom pattern configuration')
  })

  test('should validate multiple errors', ({ assert }) => {
    const config: SKUConfig = {
      validationMode: 'strict',
      validateReservedWords: true,
      reservedValues: ['TEST'],
    }

    const errors = validateSKUValue('TE$T', config)
    assert.include(errors, 'SKU can only contain alphanumeric characters, hyphens, and underscores')
  })
})

test.group('SKU Default Configuration', () => {
  test('should have sensible defaults', ({ assert }) => {
    assert.equal(DEFAULT_SKU_CONFIG.validationMode, 'strict')
    assert.equal(DEFAULT_SKU_CONFIG.caseMode, 'uppercase')
    assert.equal(DEFAULT_SKU_CONFIG.enforceUniqueness, true)
    assert.equal(DEFAULT_SKU_CONFIG.autoGenerate, false)
    assert.equal(DEFAULT_SKU_CONFIG.validateReservedWords, true)
  })

  test('should include common reserved values', ({ assert }) => {
    const reservedValues = DEFAULT_SKU_CONFIG.reservedValues || []
    assert.include(reservedValues, 'ADMIN')
    assert.include(reservedValues, 'TEST')
    assert.include(reservedValues, 'NULL')
    assert.include(reservedValues, 'DEFAULT')
    assert.include(reservedValues, 'UNDEFINED')
    assert.include(reservedValues, 'SAMPLE')
    assert.include(reservedValues, 'DEMO')
  })
})
