import { DQRule } from '../models/dq-rules.model'
import { dqValidate } from './dq-validation'

const rule = (overrides: Partial<DQRule>): DQRule => ({
  BASE_COL: 'SOME_CHAR',
  RULE_TYPE: 'HARDREGEX',
  RULE_VALUE: '',
  X: 0,
  ...overrides
})

describe('dqValidate - HARDREGEX', () => {
  it('accepts a value matching the pattern', () => {
    const rules = [rule({ RULE_VALUE: '^[A-Z]{3}\\d{4}$' })]

    expect(dqValidate(rules, 'ABC1234')).toBeTrue()
  })

  it('rejects a value not matching the pattern', () => {
    const rules = [rule({ RULE_VALUE: '^[A-Z]{3}\\d{4}$' })]

    expect(dqValidate(rules, 'abc1234')).toBeFalse()
  })

  it('treats blank/undefined/null as valid regardless of the pattern', () => {
    const rules = [rule({ RULE_VALUE: '^[A-Z]{3}\\d{4}$' })]

    expect(dqValidate(rules, '')).toBeTrue()
    expect(dqValidate(rules, undefined)).toBeTrue()
    expect(dqValidate(rules, null)).toBeTrue()
  })

  it('treats SAS special missing values as valid regardless of the pattern', () => {
    const rules = [rule({ RULE_VALUE: '^[A-Z]{3}\\d{4}$' })]

    expect(dqValidate(rules, '.')).toBeTrue()
    expect(dqValidate(rules, '.a')).toBeTrue()
    expect(dqValidate(rules, '_')).toBeTrue()
  })

  it('fails open (treats as valid) when the pattern is malformed', () => {
    const rules = [rule({ RULE_VALUE: '[unterminated' })]

    expect(dqValidate(rules, 'anything')).toBeTrue()
  })

  it('handles a more elaborate pattern (multiple character classes, quantifiers, an escaped literal dot)', () => {
    // Same email pattern used in the getdata.js mock's REGEX_HARD_COL demo.
    const rules = [rule({ RULE_VALUE: '[\\w.]+@[\\w]+\\.[a-z]{2,}' })]

    expect(dqValidate(rules, 'user@example.com')).toBeTrue()
    expect(dqValidate(rules, 'user.name@sub.example.co')).toBeTrue()
    expect(dqValidate(rules, 'not-an-email')).toBeFalse()
    // No TLD to satisfy [a-z]{2,} after the escaped dot.
    expect(dqValidate(rules, 'user@example')).toBeFalse()
  })

  it('accepts a value matching a PRX-delimited pattern (/pattern/flags, as authored for prxparse)', () => {
    const rules = [rule({ RULE_VALUE: '/^[A-Z]{3}\\d{4}$/' })]

    expect(dqValidate(rules, 'ABC1234')).toBeTrue()
  })

  it('rejects a value not matching a PRX-delimited pattern', () => {
    const rules = [rule({ RULE_VALUE: '/^[A-Z]{3}\\d{4}$/' })]

    expect(dqValidate(rules, 'abc1234')).toBeFalse()
  })

  it('applies the i flag from a PRX-delimited pattern', () => {
    const rules = [rule({ RULE_VALUE: '/^[a-z]{3}\\d{4}$/i' })]

    expect(dqValidate(rules, 'ABC1234')).toBeTrue()
  })

  it('still evaluates a second, unrelated rule on the same column', () => {
    const rules = [
      rule({ RULE_VALUE: '^[A-Z]{3}\\d{4}$' }),
      rule({ RULE_TYPE: 'NOTNULL', RULE_VALUE: '' })
    ]

    // Passes HARDREGEX (blank is exempt) but fails NOTNULL — the NOTNULL
    // rule still runs even though HARDREGEX is earlier in the array.
    expect(dqValidate(rules, '')).toBeFalse()
    // Passes NOTNULL (non-blank) but fails HARDREGEX's pattern.
    expect(dqValidate(rules, 'nope')).toBeFalse()
    // Passes both.
    expect(dqValidate(rules, 'ABC1234')).toBeTrue()
  })
})
