import Handsontable from 'handsontable'
import { makeRegexWarningRenderer } from './regex-warning-renderer'

describe('makeRegexWarningRenderer', () => {
  const buildHot = (data: any[]) => {
    const container = document.createElement('div')
    document.body.appendChild(container)

    const hot = new Handsontable(container, {
      data,
      columns: [
        { data: 'val', renderer: makeRegexWarningRenderer('^[A-Z]{3}$') },
        { data: '_____DELETE__THIS__RECORD_____' }
      ],
      licenseKey: 'non-commercial-and-evaluation'
    })
    hot.render()

    return { hot, container }
  }

  it('adds dc-warning-cell and a REGEX: title when the value fails the pattern', () => {
    const { hot, container } = buildHot([
      { val: 'abc', _____DELETE__THIS__RECORD_____: 'No' }
    ])

    const td = hot.getCell(0, 0)
    expect(td?.classList.contains('dc-warning-cell')).toBeTrue()
    expect(td?.title).toEqual('REGEX: ^[A-Z]{3}$')

    hot.destroy()
    container.remove()
  })

  it('does not add dc-warning-cell when the value matches the pattern', () => {
    const { hot, container } = buildHot([
      { val: 'ABC', _____DELETE__THIS__RECORD_____: 'No' }
    ])

    const td = hot.getCell(0, 0)
    expect(td?.classList.contains('dc-warning-cell')).toBeFalse()

    hot.destroy()
    container.remove()
  })

  it('suppresses the warning on a row marked for delete, even though the value fails the pattern', () => {
    const { hot, container } = buildHot([
      { val: 'abc', _____DELETE__THIS__RECORD_____: 'Yes' }
    ])

    const td = hot.getCell(0, 0)
    expect(td?.classList.contains('dc-warning-cell')).toBeFalse()

    hot.destroy()
    container.remove()
  })

  it('does not add dc-warning-cell for a SAS special missing value', () => {
    const { hot, container } = buildHot([
      { val: '.a', _____DELETE__THIS__RECORD_____: 'No' }
    ])

    const td = hot.getCell(0, 0)
    expect(td?.classList.contains('dc-warning-cell')).toBeFalse()

    hot.destroy()
    container.remove()
  })

  it('does not throw and never warns on a malformed pattern', () => {
    const container = document.createElement('div')
    document.body.appendChild(container)

    const hot = new Handsontable(container, {
      data: [{ val: 'abc', _____DELETE__THIS__RECORD_____: 'No' }],
      columns: [
        { data: 'val', renderer: makeRegexWarningRenderer('[unterminated') },
        { data: '_____DELETE__THIS__RECORD_____' }
      ],
      licenseKey: 'non-commercial-and-evaluation'
    })

    expect(() => hot.render()).not.toThrow()

    const td = hot.getCell(0, 0)
    expect(td?.classList.contains('dc-warning-cell')).toBeFalse()

    hot.destroy()
    container.remove()
  })

  it('handles a PRX-delimited pattern with a case-insensitive flag, as authored for prxparse', () => {
    const container = document.createElement('div')
    document.body.appendChild(container)

    const hot = new Handsontable(container, {
      data: [
        { val: 'this is dummy data', _____DELETE__THIS__RECORD_____: 'No' },
        { val: 'THE WIND WAS BLOWING', _____DELETE__THIS__RECORD_____: 'No' },
        { val: 'nothing relevant here', _____DELETE__THIS__RECORD_____: 'No' }
      ],
      columns: [
        {
          data: 'val',
          renderer: makeRegexWarningRenderer('/\\b(the|data)\\b/i')
        },
        { data: '_____DELETE__THIS__RECORD_____' }
      ],
      licenseKey: 'non-commercial-and-evaluation'
    })
    hot.render()

    expect(hot.getCell(0, 0)?.classList.contains('dc-warning-cell')).toBeFalse()
    expect(hot.getCell(1, 0)?.classList.contains('dc-warning-cell')).toBeFalse()
    expect(hot.getCell(2, 0)?.classList.contains('dc-warning-cell')).toBeTrue()

    hot.destroy()
    container.remove()
  })

  it('is display-only — the stored value is untouched', () => {
    const { hot, container } = buildHot([
      { val: 'abc', _____DELETE__THIS__RECORD_____: 'No' }
    ])

    expect(hot.getDataAtCell(0, 0)).toEqual('abc')

    hot.destroy()
    container.remove()
  })

  describe('HARDREGEX (second, optional pattern)', () => {
    // HARDREGEX already blocks submission via dqValidate/HOT's own
    // htInvalid (unchanged, untouched here) - this renderer only adds the
    // matching 'REGEX: <pattern>' title on top, so a column with only a
    // HARDREGEX rule (no SOFTREGEX at all) still tells the user why a cell
    // is red, not just that it is.
    const buildHardOnlyHot = (value: string) => {
      const container = document.createElement('div')
      document.body.appendChild(container)

      const hot = new Handsontable(container, {
        data: [{ val: value, _____DELETE__THIS__RECORD_____: 'No' }],
        columns: [
          {
            data: 'val',
            renderer: makeRegexWarningRenderer(undefined, '^[A-Z]{3}$')
          },
          { data: '_____DELETE__THIS__RECORD_____' }
        ],
        licenseKey: 'non-commercial-and-evaluation'
      })
      hot.render()

      return { hot, container }
    }

    it('sets a REGEX: title (no dc-warning-cell) when only HARDREGEX fails', () => {
      const { hot, container } = buildHardOnlyHot('abc')

      const td = hot.getCell(0, 0)
      expect(td?.classList.contains('dc-warning-cell')).toBeFalse()
      expect(td?.title).toEqual('REGEX: ^[A-Z]{3}$')

      hot.destroy()
      container.remove()
    })

    it('sets no title when the value passes HARDREGEX', () => {
      const { hot, container } = buildHardOnlyHot('ABC')

      const td = hot.getCell(0, 0)
      expect(td?.title).toEqual('')

      hot.destroy()
      container.remove()
    })

    it('suppresses the HARDREGEX title on a row marked for delete', () => {
      const container = document.createElement('div')
      document.body.appendChild(container)

      const hot = new Handsontable(container, {
        data: [{ val: 'abc', _____DELETE__THIS__RECORD_____: 'Yes' }],
        columns: [
          {
            data: 'val',
            renderer: makeRegexWarningRenderer(undefined, '^[A-Z]{3}$')
          },
          { data: '_____DELETE__THIS__RECORD_____' }
        ],
        licenseKey: 'non-commercial-and-evaluation'
      })
      hot.render()

      expect(hot.getCell(0, 0)?.title).toEqual('')

      hot.destroy()
      container.remove()
    })

    it('prefers the HARDREGEX title over SOFTREGEX when a value fails both', () => {
      const container = document.createElement('div')
      document.body.appendChild(container)

      const hot = new Handsontable(container, {
        data: [{ val: 'ab', _____DELETE__THIS__RECORD_____: 'No' }],
        columns: [
          {
            data: 'val',
            renderer: makeRegexWarningRenderer('^.{5,10}$', '^[A-Z]{3}$')
          },
          { data: '_____DELETE__THIS__RECORD_____' }
        ],
        licenseKey: 'non-commercial-and-evaluation'
      })
      hot.render()

      const td = hot.getCell(0, 0)
      // 'ab' fails HARDREGEX (not 3 uppercase letters) AND SOFTREGEX (too
      // short) - HARDREGEX wins: its title shows, and no yellow class is
      // added (HOT's own red htInvalid governs this cell instead).
      expect(td?.classList.contains('dc-warning-cell')).toBeFalse()
      expect(td?.title).toEqual('REGEX: ^[A-Z]{3}$')

      hot.destroy()
      container.remove()
    })

    it('falls through to SOFTREGEX when the value passes HARDREGEX but fails SOFTREGEX', () => {
      const container = document.createElement('div')
      document.body.appendChild(container)

      const hot = new Handsontable(container, {
        data: [{ val: 'AB', _____DELETE__THIS__RECORD_____: 'No' }],
        columns: [
          {
            data: 'val',
            renderer: makeRegexWarningRenderer('^.{5,10}$', '^[A-Z0-9]+$')
          },
          { data: '_____DELETE__THIS__RECORD_____' }
        ],
        licenseKey: 'non-commercial-and-evaluation'
      })
      hot.render()

      const td = hot.getCell(0, 0)
      // 'AB' passes HARDREGEX (uppercase/digits) but fails SOFTREGEX (too
      // short) - this is the case that was previously always inert (no
      // warning ever shown for a column with both rules).
      expect(td?.classList.contains('dc-warning-cell')).toBeTrue()
      expect(td?.title).toEqual('REGEX: ^.{5,10}$')

      hot.destroy()
      container.remove()
    })

    it('does not throw and never warns on a malformed HARDREGEX pattern', () => {
      const container = document.createElement('div')
      document.body.appendChild(container)

      const hot = new Handsontable(container, {
        data: [{ val: 'abc', _____DELETE__THIS__RECORD_____: 'No' }],
        columns: [
          {
            data: 'val',
            renderer: makeRegexWarningRenderer(undefined, '[unterminated')
          },
          { data: '_____DELETE__THIS__RECORD_____' }
        ],
        licenseKey: 'non-commercial-and-evaluation'
      })

      expect(() => hot.render()).not.toThrow()
      expect(hot.getCell(0, 0)?.title).toEqual('')

      hot.destroy()
      container.remove()
    })
  })
})
