import { describe, expect, it } from 'vitest'
import { validateValues } from './validate.js'
import { isFieldValidationError } from './errors.js'
import type { ResolvedFieldGroup } from './model.js'

const group = (fields: ResolvedFieldGroup['fields']): ResolvedFieldGroup =>
  ({ key: 'g', label: 'G', origin: 'code', location: { entityType: 'product' }, fields })

const expectInvalid = (g: ResolvedFieldGroup, v: Record<string, unknown>, field: string) => {
  try { validateValues(g, v as never); throw new Error('expected throw') }
  catch (e) { expect(isFieldValidationError(e)).toBe(true); expect((e as { field: string }).field).toBe(field) }
}

describe('validateValues', () => {
  it('required miss throws on the missing field', () => {
    expectInvalid(group([{ type: 'text', key: 'name', label: 'N', required: true }]), {}, 'name')
  })
  it('unknown key fails closed (no silent drop)', () => {
    expectInvalid(group([{ type: 'text', key: 'name', label: 'N' }]), { ghost: 'x' }, 'ghost')
  })
  it('number min/max/integer', () => {
    const g = group([{ type: 'number', key: 'n', label: 'N', min: 1, max: 10, integer: true }])
    expectInvalid(g, { n: 0 }, 'n'); expectInvalid(g, { n: 11 }, 'n'); expectInvalid(g, { n: 2.5 }, 'n')
    expect(() => validateValues(g, { n: 5 })).not.toThrow()
  })
  it('select value must be in options; multiple ⇒ array', () => {
    const g = group([{ type: 'select', key: 's', label: 'S', options: [{ value: 'a', label: 'A' }], multiple: true }])
    expectInvalid(g, { s: ['z'] }, 's'); expectInvalid(g, { s: 'a' }, 's')
    expect(() => validateValues(g, { s: ['a'] })).not.toThrow()
  })
  it('url/email/color format', () => {
    expectInvalid(group([{ type: 'email', key: 'e', label: 'E' }]), { e: 'nope' }, 'e')
    expectInvalid(group([{ type: 'url', key: 'u', label: 'U' }]), { u: 'nope' }, 'u')
    expectInvalid(group([{ type: 'color', key: 'c', label: 'C' }]), { c: 'red' }, 'c')
    expect(() => validateValues(group([{ type: 'color', key: 'c', label: 'C' }]), { c: '#aabbcc' })).not.toThrow()
  })
  it('media requires key; relationship requires targetEntityType match + ref shape', () => {
    expectInvalid(group([{ type: 'media', key: 'm', label: 'M' }]), { m: { url: 'x' } }, 'm')
    const rel = group([{ type: 'relationship', key: 'r', label: 'R', targetEntityType: 'product' }])
    expectInvalid(rel, { r: { entityType: 'user', entityId: 'u1' } }, 'r')
    expect(() => validateValues(rel, { r: { entityType: 'product', entityId: 'p1' } })).not.toThrow()
  })
})
