import rules from 'modele-social'
import Engine, { parsePublicodes } from 'publicodes'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import yaml from 'yaml'

import {
	cleanSearchParams,
	getRulesParamNames,
	getSearchParams,
	getSituationFromSearchParams,
} from '../source/components/utils/useSearchParamsSimulationSharing'

describe('identifiant court', () => {
	const questions = Object.entries(parsePublicodes(rules).parsedRules)
		.filter(([, ruleNode]) => ruleNode.rawNode['identifiant court'])
		.map(([dottedName, ruleNode]) => [
			dottedName,
			ruleNode.rawNode['identifiant court'],
		])

	it('should be unique amongst rules', () => {
		expect(questions).toHaveLength(
			new Set(questions.map(([, name]) => name)).size
		)
	})
})

describe('useSearchParamsSimulationSharing', () => {
	const engine = new Engine(
		yaml.parse(`
rule with:
  identifiant court: panta
  formule: 0
rule without:
  formule: 0
`)
	)
	const dottedNameParamName = getRulesParamNames(engine.getParsedRules())

	describe('getSearchParamsFromSituation', () => {
		it('builds search params with and without identifiant court', () => {
			expect(
				getSearchParams(
					engine,
					{ 'rule with': '2000€/mois', 'rule without': '1000€/mois' },
					dottedNameParamName,
					'€/an'
				).toString()
			).toBe(
				new URLSearchParams(
					'panta=2000€/mois&rule without=1000€/mois&unite=€/an'
				).toString()
			)
		})
		it('builds search params with object', () => {
			expect(
				getSearchParams(
					engine,
					{ 'rule without': { 1: 2, 3: { 4: '5' } } },
					dottedNameParamName,
					'€/an'
				).toString()
			).toBe(
				new URLSearchParams('rule without={"1":2,"3":{"4":"5"}}').toString() +
					'&unite=%E2%82%AC%2Fan'
			)
		})
		it('handles empty situation with proper defaults', () => {
			expect(
				getSearchParams(engine, {}, dottedNameParamName, '€/mois').toString()
			).toBe('unite=%E2%82%AC%2Fmois')
		})
	})

	describe('getSituationFromSearchParams', () => {
		it('reads search params with and without identifiant court', () => {
			expect(
				getSituationFromSearchParams(
					new URLSearchParams('panta=2000€/mois&rule without=1000€/mois'),
					dottedNameParamName
				)
			).toEqual({
				'rule with': '2000€/mois',
				'rule without': '1000€/mois',
			})
		})
		it('handles empty search params with proper defaults', () => {
			expect(
				getSituationFromSearchParams(
					new URLSearchParams(''),
					dottedNameParamName
				)
			).toEqual({})
		})
	})
})

describe('useSearchParamsSimulationSharing hook', () => {
	const { parsedRules } = parsePublicodes(
		yaml.parse(
			`
rule with:
  identifiant court: panta
  formule: 0
rule without:
  formule: 0
`
		)
	)

	const dottedNameParamName = getRulesParamNames(parsedRules)
	let setSearchParams

	beforeEach(() => {
		setSearchParams = vi.fn()
	})
	it('removes searchParams that are in situation', () => {
		const searchParams = new URLSearchParams(
			'panta=123&rule without=333&unite=€/mois'
		)
		const newSituation = getSituationFromSearchParams(
			searchParams,
			dottedNameParamName
		)
		cleanSearchParams(
			searchParams,
			setSearchParams,
			dottedNameParamName,
			Object.keys(newSituation)
		)
		expect(setSearchParams).toHaveBeenCalledWith('', { replace: true })
	})
	it("doesn't remove other search params", () => {
		const searchParams = new URLSearchParams(
			'rule without=123&utm_campaign=marketing'
		)
		const newSituation = getSituationFromSearchParams(
			searchParams,
			dottedNameParamName
		)
		cleanSearchParams(
			searchParams,
			setSearchParams,
			dottedNameParamName,
			Object.keys(newSituation)
		)
		expect(setSearchParams).toHaveBeenCalledWith('utm_campaign=marketing', {
			replace: true,
		})
	})
})