import * as R from 'ramda'
import { expect } from 'chai'
import { rules as realRules, enrichRule } from '../source/engine/rules'
import { analyse, parseAll } from '../source/engine/traverse'
import {
	getNextSteps,
	collectMissingVariables
} from '../source/engine/generateQuestions'

let stateSelector = name => null

describe('collectMissingVariables', function() {
	it('should identify missing variables', function() {
		let rawRules = [
				{
					nom: 'startHere',
					formule: 2,
					'non applicable si': 'sum . evt . ko',
					espace: 'sum'
				},
				{
					nom: 'evt',
					espace: 'sum',
					formule: { 'une possibilité': ['ko'] },
					titre: 'Truc',
					question: '?'
				},
				{ nom: 'ko', espace: 'sum . evt' }
			],
			rules = parseAll(rawRules.map(enrichRule)),
			analysis = analyse(rules, 'startHere')(stateSelector),
			result = collectMissingVariables(analysis.targets)
		expect(result).to.have.property('sum . evt . ko')
	})

	it('should identify missing variables mentioned in expressions', function() {
		let rawRules = [
				{
					nom: 'startHere',
					formule: 2,
					'non applicable si': 'evt . nyet > evt . nope',
					espace: 'sum'
				},
				{ nom: 'nope', espace: 'sum . evt' },
				{ nom: 'nyet', espace: 'sum . evt' }
			],
			rules = parseAll(rawRules.map(enrichRule)),
			analysis = analyse(rules, 'startHere')(stateSelector),
			result = collectMissingVariables(analysis.targets)

		expect(result).to.have.property('sum . evt . nyet')
		expect(result).to.have.property('sum . evt . nope')
	})

	it('should ignore missing variables in the formula if not applicable', function() {
		let rawRules = [
				{
					nom: 'startHere',
					formule: 'trois',
					'non applicable si': '3 > 2',
					espace: 'sum'
				},
				{ nom: 'trois', espace: 'sum' }
			],
			rules = parseAll(rawRules.map(enrichRule)),
			analysis = analyse(rules, 'startHere')(stateSelector),
			result = collectMissingVariables(analysis.targets)

		expect(result).to.deep.equal({})
	})

	it('should not report missing variables when "one of these" short-circuits', function() {
		let rawRules = [
				{
					nom: 'startHere',
					formule: 'trois',
					'non applicable si': { 'une de ces conditions': ['3 > 2', 'trois'] },
					espace: 'sum'
				},
				{ nom: 'trois', espace: 'sum' }
			],
			rules = parseAll(rawRules.map(enrichRule)),
			analysis = analyse(rules, 'startHere')(stateSelector),
			result = collectMissingVariables(analysis.targets)

		expect(result).to.deep.equal({})
	})

	it('should report "une possibilité" as a missing variable even though it has a formula', function() {
		let rawRules = [
				{ nom: 'startHere', formule: 'trois', espace: 'top' },
				{ nom: 'trois', formule: { 'une possibilité': ['ko'] }, espace: 'top' }
			],
			rules = parseAll(rawRules.map(enrichRule)),
			analysis = analyse(rules, 'startHere')(stateSelector),
			result = collectMissingVariables(analysis.targets)

		expect(result).to.have.property('top . trois')
	})

	it('should not report missing variables when "une possibilité" is inapplicable', function() {
		let rawRules = [
				{ nom: 'startHere', formule: 'trois', espace: 'top' },
				{
					nom: 'trois',
					formule: { 'une possibilité': ['ko'] },
					'non applicable si': 1,
					espace: 'top'
				}
			],
			rules = parseAll(rawRules.map(enrichRule)),
			analysis = analyse(rules, 'startHere')(stateSelector),
			result = collectMissingVariables(analysis.targets)

		expect(result).to.deep.equal({})
	})

	it('should not report missing variables when "une possibilité" was answered', function() {
		let mySelector = name => ({ 'top . trois': 'ko' }[name])

		let rawRules = [
				{ nom: 'startHere', formule: 'trois', espace: 'top' },
				{ nom: 'trois', formule: { 'une possibilité': ['ko'] }, espace: 'top' }
			],
			rules = parseAll(rawRules.map(enrichRule)),
			analysis = analyse(rules, 'startHere')(mySelector),
			result = collectMissingVariables(analysis.targets)

		expect(result).to.deep.equal({})
	})

	it('should report missing variables in switch statements', function() {
		let rawRules = [
				{
					nom: 'startHere',
					formule: {
						'aiguillage numérique': {
							'11 > dix': '1000%',
							'3 > dix': '1100%',
							'1 > dix': '1200%'
						}
					},
					espace: 'top'
				},
				{ nom: 'dix', espace: 'top' }
			],
			rules = parseAll(rawRules.map(enrichRule)),
			analysis = analyse(rules, 'startHere')(stateSelector),
			result = collectMissingVariables(analysis.targets)

		expect(result).to.have.property('top . dix')
	})

	it('should report missing variables in variations', function() {
		let rawRules = [
				{ nom: 'startHere', formule: { somme: ['variations'] }, espace: 'top' },
				{
					nom: 'variations',
					espace: 'top',
					formule: {
						barème: {
							assiette: 2008,
							'multiplicateur des tranches': 1000,
							variations: [
								{
									si: 'dix',
									tranches: [
										{ 'en-dessous de': 1, taux: 0.1 },
										{ de: 1, à: 2, taux: 'deux' },
										,
										{ 'au-dessus de': 2, taux: 10 }
									]
								},
								{
									si: '3 > 4',
									tranches: [
										{ 'en-dessous de': 1, taux: 0.1 },
										{ de: 1, à: 2, taux: 1.8 },
										,
										{ 'au-dessus de': 2, taux: 10 }
									]
								}
							]
						}
					}
				},
				{ nom: 'dix', espace: 'top' },
				{ nom: 'deux', espace: 'top' }
			],
			rules = parseAll(rawRules.map(enrichRule)),
			analysis = analyse(rules, 'startHere')(stateSelector),
			result = collectMissingVariables(analysis.targets)

		expect(result).to.have.property('top . dix')
		// expect(result).to.have.property('top . deux') - this is a TODO
	})

	it('should not report missing variables in irrelevant variations', function() {
		let rawRules = [
				{ nom: 'startHere', formule: { somme: ['variations'] }, espace: 'top' },
				{
					nom: 'variations',
					espace: 'top',
					formule: {
						barème: {
							assiette: 2008,
							'multiplicateur des tranches': 1000,
							variations: [
								{
									si: 'dix',
									tranches: [
										{ 'en-dessous de': 1, taux: 0.1 },
										{ de: 1, à: 2, taux: 'deux' },
										,
										{ 'au-dessus de': 2, taux: 10 }
									]
								},
								{
									si: '3 > 2',
									tranches: [
										{ 'en-dessous de': 1, taux: 0.1 },
										{ de: 1, à: 2, taux: 1.8 },
										,
										{ 'au-dessus de': 2, taux: 10 }
									]
								}
							]
						}
					}
				},
				{ nom: 'dix', espace: 'top' },
				{ nom: 'deux', espace: 'top' }
			],
			rules = parseAll(rawRules.map(enrichRule)),
			analysis = analyse(rules, 'startHere')(stateSelector),
			result = collectMissingVariables(analysis.targets)

		expect(result).to.deep.equal({})
	})

	it('should not report missing variables in switch for consequences of false conditions', function() {
		let rawRules = [
				{
					nom: 'startHere',
					formule: {
						'aiguillage numérique': {
							'8 > 10': '1000%',
							'1 > 2': 'dix'
						}
					},
					espace: 'top'
				},
				{ nom: 'dix', espace: 'top' }
			],
			rules = parseAll(rawRules.map(enrichRule)),
			analysis = analyse(rules, 'startHere')(stateSelector),
			result = collectMissingVariables(analysis.targets)

		expect(result).to.deep.equal({})
	})

	it('should report missing variables in consequence when its condition is unresolved', function() {
		let rawRules = [
				{
					nom: 'startHere',
					formule: {
						'aiguillage numérique': {
							'10 > 11': '1000%',
							'3 > dix': {
								douze: '560%',
								'1 > 2': '75015%'
							}
						}
					},
					espace: 'top'
				},
				{ nom: 'douze', espace: 'top' },
				{ nom: 'dix', espace: 'top' }
			],
			rules = parseAll(rawRules.map(enrichRule)),
			analysis = analyse(rules, 'startHere')(stateSelector),
			result = collectMissingVariables(analysis.targets)

		expect(result).to.have.property('top . dix')
		expect(result).to.have.property('top . douze')
	})

	it('should not report missing variables when a switch short-circuits', function() {
		let rawRules = [
				{
					nom: 'startHere',
					formule: {
						'aiguillage numérique': {
							'11 > 10': '1000%',
							'3 > dix': '1100%',
							'1 > dix': '1200%'
						}
					},
					espace: 'top'
				},
				{ nom: 'dix', espace: 'top' }
			],
			rules = parseAll(rawRules.map(enrichRule)),
			analysis = analyse(rules, 'startHere')(stateSelector),
			result = collectMissingVariables(analysis.targets)

		expect(result).to.deep.equal({})
	})
})

describe('nextSteps', function() {
	it('should generate questions', function() {
		let rawRules = [
				{ nom: 'sum', formule: { somme: [2, 'deux'] }, espace: 'top' },
				{
					nom: 'deux',
					formule: 2,
					'non applicable si': "top . sum . evt = 'ko'",
					espace: 'top'
				},
				{
					nom: 'evt',
					espace: 'top . sum',
					formule: { 'une possibilité': ['ko'] },
					titre: 'Truc',
					question: '?'
				},
				{ nom: 'ko', espace: 'top . sum . evt' }
			],
			rules = parseAll(rawRules.map(enrichRule)),
			analysis = analyse(rules, 'sum')(stateSelector),
			result = getNextSteps(stateSelector, analysis)

		expect(result).to.have.lengthOf(1)
		expect(result[0]).to.equal('top . sum . evt')
	})

	it('should generate questions from the real rules', function() {
		let rules = parseAll(realRules.map(enrichRule)),
			analysis = analyse(rules, 'surcoût CDD')(stateSelector),
			missing = collectMissingVariables(analysis.targets),
			result = getNextSteps(stateSelector, analysis)

		// expect(objectives).to.have.lengthOf(4)

		// expect(missing).to.have.property('contrat salarié . type de contrat')
		// expect(missing).to.have.property('contrat salarié . CDD . événement')
		// expect(missing).to.have.property('contrat salarié . CDD . motif')
		// expect(missing).to.have.property('contrat salarié . salaire de base')
		// expect(missing).to.have.property('contrat salarié . CDD . contrat jeune vacances')
		// expect(missing).to.have.property('contrat salarié . CDD . durée contrat')
		// expect(missing).to.have.property('contrat salarié . CDD . congés non pris')

		// One question per missing variable !
		// expect(R.keys(missing)).to.have.lengthOf(7)
		// expect(result).to.have.lengthOf(7)

		// expect(R.path(["question","props","label"])(result[0])).to.equal("Quelle est la nature du contrat de travail ?")
		// expect(R.path(["question","props","label"])(result[1])).to.equal("Pensez-vous être confronté à l'un de ces événements au cours du contrat ?")
		// expect(R.path(["question","props","label"])(result[2])).to.equal("Quel est le motif de recours au CDD ?")
		// expect(R.path(["question","props","label"])(result[3])).to.equal("Quel est le salaire brut ?")
		// expect(R.path(["question","props","label"])(result[4])).to.equal("Est-ce un contrat jeune vacances ?")
		// expect(R.path(["question","props","label"])(result[5])).to.equal("Quelle est la durée du contrat ?")
		// expect(R.path(["question","props","label"])(result[6])).to.equal("Combien de jours de congés ne seront pas pris ?")
	})

	it('should generate questions from the real rules, experimental version', function() {
		let stateSelector = name =>
			({
				'contrat salarié . type de contrat': 'CDI',
				'entreprise . effectif': '50'
			}[name])

		let rules = parseAll(realRules.map(enrichRule)),
			analysis = analyse(rules, 'salaire')(stateSelector),
			missing = collectMissingVariables(analysis.targets),
			result = getNextSteps(stateSelector, analysis)

		expect(result[0]).to.equal('contrat salarié . salaire de base')
		expect(result[1]).to.equal('contrat salarié . temps partiel')
	})

	it('should ask "motif CDD" if "CDD" applies', function() {
		let stateSelector = name =>
			({
				'contrat salarié . type de contrat': 'CDD',
				'contrat salarié . salaire de base': '2300'
			}[name])

		let rules = parseAll(realRules.map(enrichRule)),
			analysis = analyse(rules, 'salaire net')(stateSelector),
			missing = collectMissingVariables(analysis.targets),
			result = getNextSteps(stateSelector, analysis)

		expect(result).to.include('contrat salarié . CDD . motif')
	})
})