import {
	pushNewReplaceVar, mapCustomFields, mapCustomTaxonomies, prepareCustomFieldForDispatch,
	prepareCustomTaxonomyForDispatch,
	replaceSpaces,
} from "../../src/helpers/replacementVariableHelpers";
import { UPDATE_REPLACEMENT_VARIABLE, UPDATE_REPLACEMENT_VARIABLES_BATCH } from "../../src/redux/actions/snippetEditor";

describe( "replaceSpaces", () => {
	it( "replaces single spaces in a string with underscores", () => {
		const spaceString = "I have single spaces between my words";

		const expected = "I_have_single_spaces_between_my_words";

		const actual = replaceSpaces( spaceString );

		expect( actual ).toEqual( expected );
	} );

	it( "replaces multiple spaces in a string with the same number of underscores", () => {
		const spaceString = "Two  Three   Four    spaces";

		const expected = "Two__Three___Four____spaces";

		const actual = replaceSpaces( spaceString );

		expect( actual ).toEqual( expected );
	} );

	it( "replaces leading and trailing spaces in a string with the same number of underscores", () => {
		const spaceString = "  two spaces before and three spaces after   ";

		const expected = "__two_spaces_before_and_three_spaces_after___";

		const actual = replaceSpaces( spaceString );

		expect( actual ).toEqual( expected );
	} );
} );

describe( "prepareCustomFieldForDispatch", () => {
	it( "returns an object containing a name and a label", () => {
		const nameString = "custom field name";

		const expected = [ "name", "label" ].sort();

		const actual = prepareCustomFieldForDispatch( nameString );

		expect( typeof actual ).toEqual( "object" );
		expect( Object.keys( actual ).sort() ).toEqual( expected );
	} );

	it( "returns a name that is prefixed with 'cf_'", () => {
		const nameString = "custom field name";

		const expected = "cf_custom_field_name";

		const { name: actual } = prepareCustomFieldForDispatch( nameString );

		expect( actual ).toEqual( expected );
	} );

	it( "returns a label with the first letter capitalized, no replaced spaces, and appended with (custom field)", () => {
		const nameString = "custom field name";

		const expected = "Custom field name (custom field)";

		const { label: actual } = prepareCustomFieldForDispatch( nameString );

		expect( actual ).toEqual( expected );
	} );
} );

describe( "prepareCustomTaxonomyForDispatch", () => {
	it( "returns an object containing a name, label, descriptionName and a descriptionLabel", () => {
		const nameString = "custom taxonomy name";

		const expected = [ "name", "label", "descriptionName", "descriptionLabel" ].sort();

		const actual = prepareCustomTaxonomyForDispatch( nameString );

		expect( typeof actual ).toEqual( "object" );
		expect( Object.keys( actual ).sort() ).toEqual( expected );
	} );

	it( "returns a name that is prefixed with 'ct_'", () => {
		const nameString = "custom taxonomy name";

		const expected = "ct_custom_taxonomy_name";

		const { name: actual } = prepareCustomTaxonomyForDispatch( nameString );

		expect( actual ).toEqual( expected );
	} );

	it( "returns a label with the first letter capitalized, no replaced spaces, and appended with (custom taxonomy)", () => {
		const nameString = "custom taxonomy name";

		const expected = "Custom taxonomy name (custom taxonomy)";

		const { label: actual } = prepareCustomTaxonomyForDispatch( nameString );

		expect( actual ).toEqual( expected );
	} );

	it( "returns a name for the description that is prefixed with 'ct_desc_'", () => {
		const nameString = "custom taxonomy name";

		const expected = "ct_custom_taxonomy_name";

		const { name: actual } = prepareCustomTaxonomyForDispatch( nameString );

		expect( actual ).toEqual( expected );
	} );

	it( "returns a label with the first letter capitalized, no replaced spaces, and appended with (custom taxonomy)", () => {
		const nameString = "custom taxonomy name";

		const expected = "Custom taxonomy name (custom taxonomy)";

		const { label: actual } = prepareCustomTaxonomyForDispatch( nameString );

		expect( actual ).toEqual( expected );
	} );
} );

describe( "mapCustomFields", () => {
	const replaceVars = {
		replaceVar1: "replaceValue1",
		replaceVar2: "replaceValue2",
		replaceVar3: "replaceValue3",
		/* eslint-disable */
		custom_fields: {
			"i only have spaces": "value1",
			i_only_have_underscores: "value2",
		},
		/* eslint-enable */
	};

	const store = {
		dispatch: jest.fn(),
	};

	it( "dispatches the SNIPPET_EDITOR_UPDATE_REPLACEMENT_VARIABLE action to redux", () => {
		mapCustomFields( replaceVars, store );

		expect( store.dispatch ).toHaveBeenCalledWith( expect.objectContaining( {
			type: UPDATE_REPLACEMENT_VARIABLE,
		} ) );
	} );

	it( "passes a label that contains ' (custom fields)'", () => {
		mapCustomFields( replaceVars, store );

		expect( store.dispatch ).toHaveBeenCalledWith( expect.objectContaining( {
			label: expect.stringContaining( " (custom field)" ),
		} ) );
	} );

	it( "passes a name that is prefixed with 'cf_'", () => {
		mapCustomFields( replaceVars, store );

		expect( store.dispatch ).toHaveBeenCalledWith( expect.objectContaining( {
			name: expect.stringContaining( "cf_" ),
		} ) );
	} );

	it( "removes the old custom_fields object from the replace_vars", () => {
		const actual = mapCustomFields( replaceVars, store );

		expect( actual ).not.toBe( expect.objectContaining( {
			/* eslint-disable */
			custom_fields: expect.any( Object ),
			/* eslint-enable */
		} ) );
	} );
} );

describe( "mapCustomTaxonomies", () => {
	const replaceVars = {
		replaceVar1: "replaceValue1",
		replaceVar2: "replaceValue2",
		replaceVar3: "replaceValue3",
		/* eslint-disable */
		custom_taxonomies: {
			customTaxOne: {
				name: "customTaxOne",
				description: "customTaxOneDescription",
			},
			customTaxTwo: {
				name: "customTaxTwo",
				description: "customTaxTwoDescription",
			},
		},
		/* eslint-enable */
	};

	const store = {
		dispatch: jest.fn(),
	};

	it( "dispatches the SNIPPET_EDITOR_UPDATE_REPLACEMENT_VARIABLE action to redux twice per custom taxonomy", () => {
		mapCustomTaxonomies( replaceVars, store );

		expect( store.dispatch ).toHaveBeenCalledWith( expect.objectContaining( {
			type: UPDATE_REPLACEMENT_VARIABLES_BATCH,
		} ) );
		expect( store.dispatch ).toHaveBeenCalledTimes( 1 );
	} );

	it( "passes a name that is prefixed with 'ct_' and a label that contains ' (custom taxonomies)'", () => {
		mapCustomTaxonomies( replaceVars, store );
		expect( store.dispatch ).toHaveBeenCalledWith( expect.objectContaining( {
			type: UPDATE_REPLACEMENT_VARIABLES_BATCH,
			// eslint-disable-next-line camelcase
			updatedVariables: { ct_customTaxOne: { label: "CustomTaxOne (custom taxonomy)", value: "customTaxOne" }, ct_customTaxTwo: { label: "CustomTaxTwo (custom taxonomy)", value: "customTaxTwo" }, ct_desc_customTaxOne: { label: "CustomTaxOne description (custom taxonomy)", value: "customTaxOneDescription" }, ct_desc_customTaxTwo: { label: "CustomTaxTwo description (custom taxonomy)", value: "customTaxTwoDescription" } },
		} ) );
	} );

	it( "removes the old custom_taxonomies object from the replace_vars", () => {
		const actual = mapCustomTaxonomies( replaceVars, store );

		expect( actual ).not.toBe( expect.objectContaining( {
			/* eslint-disable */
			custom_taxonomies: expect.any( Object ),
			/* eslint-enable */
		} ) );
	} );
} );

describe( "pushNewReplaceVar", () => {
	it( "pushes an action to an array", () => {
		const oldArray = [ { name: "object1" } ];
		const action = {
			name: "test_name",
			label: "Nice custom label",
			value: "testValue",
		};

		const expected =  [
			{
				name: "object1",
			},
			{
				name: "test_name",
				label: "Nice custom label",
				value: "testValue",
			},
		];

		const actual = pushNewReplaceVar( oldArray, action );

		expect( actual ).toEqual( expected );
	} );

	it( "calls createLabelFromName if no label was supplied in the action", () => {
		const oldArray = [ { name: "object1" } ];
		const action = {
			name: "test_name",
			label: "",
			value: "testValue",
		};

		const expected =  [
			{
				name: "object1",
			},
			{
				name: "test_name",
				label: "Test name",
				value: "testValue",
			},
		];

		const actual = pushNewReplaceVar( oldArray, action );

		expect( actual ).toEqual( expected );
	} );
} );
