import { describe, it, expect } from 'vitest'
import {
  FIELD_KEY_PATTERN,
  FIELD_TYPES,
  SELECT_TYPES,
  validateDefinitionInput,
  validateUpdateDefinitionInput,
  validateOptionInput,
} from '@/lib/intake/field-builder'

describe('field-builder — FIELD_KEY_PATTERN', () => {
  it('accepts canonical snake_case keys', () => {
    expect(FIELD_KEY_PATTERN.test('supplier_motivation')).toBe(true)
    expect(FIELD_KEY_PATTERN.test('block6_cost_estimate')).toBe(true)
    expect(FIELD_KEY_PATTERN.test('key123')).toBe(true)
  })

  it('rejects keys with caps, special chars, leading digit, too short, too long', () => {
    expect(FIELD_KEY_PATTERN.test('SupplierMotivation')).toBe(false)
    expect(FIELD_KEY_PATTERN.test('supplier-motivation')).toBe(false)
    expect(FIELD_KEY_PATTERN.test('1invalid')).toBe(false)
    expect(FIELD_KEY_PATTERN.test('ab')).toBe(false)
    expect(FIELD_KEY_PATTERN.test('a' + 'x'.repeat(50))).toBe(false)
    expect(FIELD_KEY_PATTERN.test('')).toBe(false)
    expect(FIELD_KEY_PATTERN.test('with space')).toBe(false)
  })
})

describe('field-builder — SELECT_TYPES', () => {
  it('has exactly the three select-style types', () => {
    expect(SELECT_TYPES.has('select')).toBe(true)
    expect(SELECT_TYPES.has('multiselect')).toBe(true)
    expect(SELECT_TYPES.has('hybrid_select')).toBe(true)
    expect(SELECT_TYPES.has('text')).toBe(false)
    expect(SELECT_TYPES.has('boolean')).toBe(false)
  })
})

describe('field-builder — validateDefinitionInput (create)', () => {
  const BASE = {
    field_key: 'supplier_motivation',
    block: 6 as number,
    label_de: 'Motivation Lieferant',
    label_en: null,
    helptext_de: null,
    helptext_en: null,
    field_type: 'textarea' as const,
    is_required: false,
    visible_if_text: null,
    sort_order: 0,
  }

  it('accepts a complete input', () => {
    const r = validateDefinitionInput(BASE)
    expect(r.ok).toBe(true)
  })

  it('rejects empty field_key', () => {
    const r = validateDefinitionInput({ ...BASE, field_key: '' })
    expect(r.ok).toBe(false)
    if (!r.ok) expect(r.error).toBe('field_key_required')
  })

  it('rejects field_key not matching pattern', () => {
    const r = validateDefinitionInput({ ...BASE, field_key: 'Invalid-Key' })
    expect(r.ok).toBe(false)
    if (!r.ok) expect(r.error).toBe('field_key_invalid')
  })

  it('rejects empty label_de', () => {
    const r = validateDefinitionInput({ ...BASE, label_de: '   ' })
    expect(r.ok).toBe(false)
    if (!r.ok) expect(r.error).toBe('label_de_required')
  })

  it('rejects block out of range', () => {
    expect(validateDefinitionInput({ ...BASE, block: 0 }).ok).toBe(false)
    expect(validateDefinitionInput({ ...BASE, block: 10 }).ok).toBe(false)
    expect(validateDefinitionInput({ ...BASE, block: 1.5 }).ok).toBe(false)
  })

  it('rejects unknown field_type', () => {
    const r = validateDefinitionInput({ ...BASE, field_type: 'nonsense' as never })
    expect(r.ok).toBe(false)
    if (!r.ok) expect(r.error).toBe('unknown_field_type')
  })

  it('rejects negative sort_order', () => {
    const r = validateDefinitionInput({ ...BASE, sort_order: -1 })
    expect(r.ok).toBe(false)
    if (!r.ok) expect(r.error).toBe('sort_order_invalid')
  })

  it('accepts well-formed visible_if JSON', () => {
    const r = validateDefinitionInput({
      ...BASE,
      visible_if_text: '{"field":"intake_type","equals":"lsc_workshop"}',
    })
    expect(r.ok).toBe(true)
    if (r.ok) {
      expect(r.visibleIf).toEqual({ field: 'intake_type', equals: 'lsc_workshop' })
    }
  })

  it('rejects malformed visible_if JSON', () => {
    const r = validateDefinitionInput({ ...BASE, visible_if_text: 'not json' })
    expect(r.ok).toBe(false)
    if (!r.ok) expect(r.error).toBe('visible_if_invalid_json')
  })

  it('treats empty visible_if_text as null', () => {
    const r = validateDefinitionInput({ ...BASE, visible_if_text: '' })
    expect(r.ok).toBe(true)
    if (r.ok) expect(r.visibleIf).toBeNull()
  })

  it('all canonical FIELD_TYPES are accepted', () => {
    for (const ft of FIELD_TYPES) {
      const r = validateDefinitionInput({ ...BASE, field_type: ft })
      expect(r.ok).toBe(true)
    }
  })
})

describe('field-builder — validateUpdateDefinitionInput', () => {
  const BASE = {
    block: 1,
    label_de: 'Test',
    label_en: null,
    helptext_de: null,
    helptext_en: null,
    is_required: false,
    visible_if_text: null,
    sort_order: 0,
    is_active: true,
  }

  it('accepts a complete input', () => {
    expect(validateUpdateDefinitionInput(BASE).ok).toBe(true)
  })

  it('rejects empty label_de', () => {
    const r = validateUpdateDefinitionInput({ ...BASE, label_de: '' })
    expect(r.ok).toBe(false)
    if (!r.ok) expect(r.error).toBe('label_de_required')
  })

  it('rejects block out of range', () => {
    expect(validateUpdateDefinitionInput({ ...BASE, block: 0 }).ok).toBe(false)
    expect(validateUpdateDefinitionInput({ ...BASE, block: 99 }).ok).toBe(false)
  })

  it('rejects malformed visible_if JSON', () => {
    const r = validateUpdateDefinitionInput({ ...BASE, visible_if_text: '{bad' })
    expect(r.ok).toBe(false)
    if (!r.ok) expect(r.error).toBe('visible_if_invalid_json')
  })
})

describe('field-builder — validateOptionInput', () => {
  const BASE = {
    option_value: 'lsc_workshop',
    label_de: 'LSC Workshop',
    label_en: null,
    sort_order: 10,
    is_active: true,
  }

  it('accepts a complete input', () => {
    expect(validateOptionInput(BASE).ok).toBe(true)
  })

  it('rejects empty option_value', () => {
    const r = validateOptionInput({ ...BASE, option_value: '' })
    expect(r.ok).toBe(false)
    if (!r.ok) expect(r.error).toBe('option_value_required')
  })

  it('rejects empty label_de', () => {
    const r = validateOptionInput({ ...BASE, label_de: ' ' })
    expect(r.ok).toBe(false)
    if (!r.ok) expect(r.error).toBe('label_de_required')
  })

  it('rejects negative sort_order', () => {
    expect(validateOptionInput({ ...BASE, sort_order: -1 }).ok).toBe(false)
    expect(validateOptionInput({ ...BASE, sort_order: 1.5 }).ok).toBe(false)
  })
})
