import { describe, expect, it } from 'vitest'

import { isQuestionHardFilteredAfterAnswers } from '@/lib/gekanatorQuestionFilters'

import type {
    GekanatorAnswerLog,
    GekanatorAnswerValue,
    GekanatorQuestion,
    GekanatorQuestionCondition,
} from '@/lib/gekanator'


const question = (
    condition:  GekanatorQuestionCondition,
): GekanatorQuestion => ({
  id: `${ condition.type }:candidate`,
  text: 'candidate?',
  kind: condition.type === 'source'
      ? 'source'
      : condition.type.startsWith ('original-')
	? 'original_date'
	: condition.type.startsWith ('title-')
	  ? 'title'
	  : 'tag',
  condition,
  source: 'default',
  priorityWeight: 1,
  test: () => false,
})


const answer = (
    condition:  GekanatorQuestionCondition,
    value:      GekanatorAnswerValue,
): GekanatorAnswerLog => ({
  questionId: 'previous',
  questionText: 'previous?',
  questionCondition: condition,
  answer: value,
  originalAnswer: value,
})


const blocked = (
    candidate:  GekanatorQuestionCondition,
    previous:   GekanatorQuestionCondition,
    value:      GekanatorAnswerValue,
): boolean =>
    isQuestionHardFilteredAfterAnswers (question (candidate), [answer (previous, value)])


describe('isQuestionHardFilteredAfterAnswers', () => {
  it('blocks only contradictory or redundant month questions after a yes answer', () => {
    const previous: GekanatorQuestionCondition = { type: 'original-month', month: 12 }

    expect(blocked ({ type: 'original-month', month: 12 }, previous, 'yes')).toBe(true)
    expect(blocked ({ type: 'original-month', month: 2 }, previous, 'yes')).toBe(true)
    expect(blocked ({ type: 'original-month-day', monthDay: '2-14' }, previous, 'yes'))
      .toBe(true)
    expect(blocked ({ type: 'original-month-day', monthDay: '12-25' }, previous, 'yes'))
      .toBe(false)
    expect(blocked ({ type: 'original-year', year: 2024 }, previous, 'yes')).toBe(false)
    expect(blocked ({ type: 'source', host: 'example.com' }, previous, 'yes')).toBe(false)
    expect(blocked ({ type: 'tag', key: 'character:喜多郁代' }, previous, 'yes')).toBe(false)
  })

  it('blocks same-month facts after a no answer', () => {
    const previous: GekanatorQuestionCondition = { type: 'original-month', month: 12 }

    expect(blocked ({ type: 'original-month', month: 12 }, previous, 'no')).toBe(true)
    expect(blocked ({ type: 'original-month', month: 2 }, previous, 'no')).toBe(false)
    expect(blocked ({ type: 'original-month-day', monthDay: '12-25' }, previous, 'no'))
      .toBe(true)
    expect(blocked ({ type: 'original-month-day', monthDay: '2-14' }, previous, 'no'))
      .toBe(false)
  })

  it('blocks all month and month-day questions after a month-day yes answer', () => {
    const previous: GekanatorQuestionCondition = {
      type: 'original-month-day',
      monthDay: '12-25',
    }

    expect(blocked ({ type: 'original-month', month: 12 }, previous, 'yes')).toBe(true)
    expect(blocked ({ type: 'original-month', month: 2 }, previous, 'yes')).toBe(true)
    expect(blocked ({ type: 'original-month-day', monthDay: '12-25' }, previous, 'yes'))
      .toBe(true)
    expect(blocked ({ type: 'original-month-day', monthDay: '12-26' }, previous, 'yes'))
      .toBe(true)
  })

  it('blocks the same month-day only after a month-day no answer', () => {
    const previous: GekanatorQuestionCondition = {
      type: 'original-month-day',
      monthDay: '12-25',
    }

    expect(blocked ({ type: 'original-month-day', monthDay: '12-25' }, previous, 'no'))
      .toBe(true)
    expect(blocked ({ type: 'original-month-day', monthDay: '12-26' }, previous, 'no'))
      .toBe(false)
    expect(blocked ({ type: 'original-month', month: 12 }, previous, 'no')).toBe(false)
  })

  it('blocks year and source as single-value facts', () => {
    expect(blocked (
      { type: 'original-year', year: 2025 },
      { type: 'original-year', year: 2024 },
      'yes',
    )).toBe(true)
    expect(blocked (
      { type: 'original-year', year: 2024 },
      { type: 'original-year', year: 2024 },
      'no',
    )).toBe(true)
    expect(blocked (
      { type: 'source', host: 'b.example' },
      { type: 'source', host: 'a.example' },
      'yes',
    )).toBe(true)
    expect(blocked (
      { type: 'source', host: 'b.example' },
      { type: 'source', host: 'a.example' },
      'no',
    )).toBe(false)
  })

  it('does not hard-filter partial, probably_no, or unknown fact answers', () => {
    const previous: GekanatorQuestionCondition = { type: 'original-month', month: 12 }
    const candidate: GekanatorQuestionCondition = { type: 'original-month', month: 2 }

    expect(blocked (candidate, previous, 'partial')).toBe(false)
    expect(blocked (candidate, previous, 'probably_no')).toBe(false)
    expect(blocked (candidate, previous, 'unknown')).toBe(false)
  })

  it('keeps title-length hard redundancy for yes and no only', () => {
    const previous: GekanatorQuestionCondition = {
      type: 'title-length-at-least',
      length: 30,
    }

    expect(blocked ({ type: 'title-length-at-least', length: 20 }, previous, 'yes'))
      .toBe(true)
    expect(blocked ({ type: 'title-length-at-least', length: 40 }, previous, 'yes'))
      .toBe(false)
    expect(blocked ({ type: 'title-length-at-least', length: 40 }, previous, 'no'))
      .toBe(true)
    expect(blocked ({ type: 'title-length-at-least', length: 20 }, previous, 'no'))
      .toBe(false)
    expect(blocked ({ type: 'title-length-at-least', length: 20 }, previous, 'partial'))
      .toBe(false)
  })
})
