// @flow
import React from 'react';
import { expect } from 'chai';
import { mount } from 'enzyme';
import sinon from 'sinon';

import { NewEntityModal as C } from './NewEntityModal.jsx';
import test_dbs from '@test/test_dbs.json';
import test_dfs from '@test/test_dfs.json';
import test_libs from '@test/test_libs.json';
import test_algs from '@test/test_algs.json';
import test_tcs from '@test/test_tcs.json';
import test_exps from '@test/test_exps.json';

type Props = {
	isOpen: boolean,
	toggle: () => mixed,
	entity: BeatEntity,
	copyObj?: BeatObject,
	create: (string, BeatObject[], BeatObject[], ?BeatObject) => mixed,
	data: BeatObject[],
	toolchains: BeatObject[],
	algorithms: BeatObject[],
	// if true, the name is being changed but the version is stuck at 1 (for copying or creating new)
	// if false, the name is stuck and the version is incremented (for making a new version)
	nameOrVersion: boolean,
};

describe('<NewEntityModal />', () => {
	let wrapper;
	const entities = [
		'database',
		'dataformat',
		'library',
		'algorithm',
		'toolchain',
		'experiment',
		'plotter',
		'plotterparameter',
	];
	const isOpen = true;
	const create = sinon.spy();
	const toggle = sinon.spy();


	afterEach(() => {
		if(wrapper && wrapper.unmount)
			wrapper.unmount();
	});

	it(`has 9 required props and is missing 1 optional`, () => {
		const entity = 'database';
		const nameOrVersion = true;
		wrapper = mount(
			<C
				isOpen={isOpen}
				toggle={toggle}
				create={create}
				entity={entity}
				data={test_dbs}
				algorithms={test_algs}
				toolchains={test_tcs}
				nameOrVersion={nameOrVersion}
			/>
		);

		expect(wrapper).to.have.props(
			['isOpen', 'toggle', 'create', 'entity', 'data', 'algorithms', 'toolchains', 'nameOrVersion']
		).deep.equal(
			[isOpen, toggle, create, entity, test_dbs, test_algs, test_tcs, nameOrVersion]
		);

		expect(wrapper).to.not.have.props(
			['copyObj']
		);
	});

	it(`has all 10 props`, () => {
		const entity = 'database';
		const nameOrVersion = true;
		const copyObj = test_dbs[0];
		wrapper = mount(
			<C
				isOpen={isOpen}
				toggle={toggle}
				create={create}
				entity={entity}
				data={test_dbs}
				algorithms={test_algs}
				toolchains={test_tcs}
				nameOrVersion={nameOrVersion}
				copyObj={copyObj}
			/>
		);

		expect(wrapper).to.have.props(
			['isOpen', 'toggle', 'create', 'entity', 'data', 'algorithms', 'toolchains', 'nameOrVersion', 'copyObj']
		).deep.equal(
			[isOpen, toggle, create, entity, test_dbs, test_algs, test_tcs, nameOrVersion, copyObj]
		);
	});

	describe('for databases', () => {
		const entity = 'database';
		it(`properly handles creating a new object`, () => {
			const nameOrVersion = true;
			const copyObj = undefined;
			const newNameSegs = ['', `1`];
			wrapper = mount(
				<C
					isOpen={isOpen}
					toggle={toggle}
					create={create}
					entity={entity}
					data={test_dbs}
					algorithms={test_algs}
					toolchains={test_tcs}
					nameOrVersion={nameOrVersion}
					copyObj={copyObj}
				/>
			);

			expect(wrapper.state('numSegs')).to.equal(2);
			expect(wrapper.state('nameSegs')).to.deep.equal(newNameSegs);
			const inputs = wrapper.find('input');
			expect(inputs).to.have.length(2);
			expect(inputs.get(0).props.value).to.equal(newNameSegs[0]);
			expect(inputs.get(0).props.disabled).to.equal(false);
			expect(inputs.get(1).props.value).to.equal(newNameSegs[1]);
			expect(inputs.get(1).props.disabled).to.equal(true);
		});

		it(`properly handles copying`, () => {
			const nameOrVersion = true;
			const copyObj = test_dbs[0];
			const oldNameSegs = copyObj.name.split('/');
			const copyVersion = Number.parseInt(oldNameSegs.slice(-1)[0]);
			const newNameSegs = [...oldNameSegs.slice(0, -1), `1`];
			wrapper = mount(
				<C
					isOpen={isOpen}
					toggle={toggle}
					create={create}
					entity={entity}
					data={test_dbs}
					algorithms={test_algs}
					toolchains={test_tcs}
					nameOrVersion={nameOrVersion}
					copyObj={copyObj}
				/>
			);

			expect(wrapper.state('numSegs')).to.equal(2);
			expect(wrapper.state('nameSegs')).to.deep.equal(newNameSegs);
			const inputs = wrapper.find('input');
			expect(inputs).to.have.length(2);
			expect(inputs.get(0).props.value).to.equal(newNameSegs[0]);
			expect(inputs.get(0).props.disabled).to.equal(false);
			expect(inputs.get(1).props.value).to.equal(newNameSegs[1]);
			expect(inputs.get(1).props.disabled).to.equal(true);
		});

		it(`properly handles creating a new version`, () => {
			const nameOrVersion = false;
			const copyObj = test_dbs[0];
			const oldNameSegs = copyObj.name.split('/');
			const copyVersion = Number.parseInt(oldNameSegs.slice(-1)[0]);
			const newNameSegs = [...oldNameSegs.slice(0, -1), `${ copyVersion + 1 }`];
			wrapper = mount(
				<C
					isOpen={isOpen}
					toggle={toggle}
					create={create}
					entity={entity}
					data={test_dbs}
					algorithms={test_algs}
					toolchains={test_tcs}
					nameOrVersion={nameOrVersion}
					copyObj={copyObj}
				/>
			);

			expect(wrapper.state('numSegs')).to.equal(2);
			expect(wrapper.state('nameSegs')).to.deep.equal(newNameSegs);
			const inputs = wrapper.find('input');
			expect(inputs).to.have.length(2);
			expect(inputs.get(0).props.value).to.equal(newNameSegs[0]);
			expect(inputs.get(0).props.disabled).to.equal(true);
			expect(inputs.get(1).props.value).to.equal(newNameSegs[1]);
			expect(inputs.get(1).props.disabled).to.equal(true);
		});
	});

	describe('for databases', () => {
		const entity = 'database';
		it(`properly handles creating a new object`, () => {
			const nameOrVersion = true;
			const copyObj = undefined;
			const newNameSegs = ['', `1`];
			wrapper = mount(
				<C
					isOpen={isOpen}
					toggle={toggle}
					create={create}
					entity={entity}
					data={test_dbs}
					algorithms={test_algs}
					toolchains={test_tcs}
					nameOrVersion={nameOrVersion}
					copyObj={copyObj}
				/>
			);

			expect(wrapper.state('numSegs')).to.equal(2);
			expect(wrapper.state('nameSegs')).to.deep.equal(newNameSegs);
			const inputs = wrapper.find('input');
			expect(inputs).to.have.length(2);
			expect(inputs.get(0).props.value).to.equal(newNameSegs[0]);
			expect(inputs.get(0).props.disabled).to.equal(false);
			expect(inputs.get(1).props.value).to.equal(newNameSegs[1]);
			expect(inputs.get(1).props.disabled).to.equal(true);
		});

		it(`properly handles copying`, () => {
			const nameOrVersion = true;
			const copyObj = test_dbs[0];
			const oldNameSegs = copyObj.name.split('/');
			const copyVersion = Number.parseInt(oldNameSegs.slice(-1)[0]);
			const newNameSegs = [...oldNameSegs.slice(0, -1), `1`];
			wrapper = mount(
				<C
					isOpen={isOpen}
					toggle={toggle}
					create={create}
					entity={entity}
					data={test_dbs}
					algorithms={test_algs}
					toolchains={test_tcs}
					nameOrVersion={nameOrVersion}
					copyObj={copyObj}
				/>
			);

			expect(wrapper.state('numSegs')).to.equal(2);
			expect(wrapper.state('nameSegs')).to.deep.equal(newNameSegs);
			const inputs = wrapper.find('input');
			expect(inputs).to.have.length(2);
			expect(inputs.get(0).props.value).to.equal(newNameSegs[0]);
			expect(inputs.get(0).props.disabled).to.equal(false);
			expect(inputs.get(1).props.value).to.equal(newNameSegs[1]);
			expect(inputs.get(1).props.disabled).to.equal(true);
		});

		it(`properly handles creating a new version`, () => {
			const nameOrVersion = false;
			const copyObj = test_dbs[0];
			const oldNameSegs = copyObj.name.split('/');
			const copyVersion = Number.parseInt(oldNameSegs.slice(-1)[0]);
			const newNameSegs = [...oldNameSegs.slice(0, -1), `${ copyVersion + 1 }`];
			wrapper = mount(
				<C
					isOpen={isOpen}
					toggle={toggle}
					create={create}
					entity={entity}
					data={test_dbs}
					algorithms={test_algs}
					toolchains={test_tcs}
					nameOrVersion={nameOrVersion}
					copyObj={copyObj}
				/>
			);

			expect(wrapper.state('numSegs')).to.equal(2);
			expect(wrapper.state('nameSegs')).to.deep.equal(newNameSegs);
			const inputs = wrapper.find('input');
			expect(inputs).to.have.length(2);
			expect(inputs.get(0).props.value).to.equal(newNameSegs[0]);
			expect(inputs.get(0).props.disabled).to.equal(true);
			expect(inputs.get(1).props.value).to.equal(newNameSegs[1]);
			expect(inputs.get(1).props.disabled).to.equal(true);
		});
	});

	describe('for algorithms', () => {
		const entity = 'algorithm';
		it(`properly handles creating a new object`, () => {
			const nameOrVersion = true;
			const copyObj = undefined;
			const newNameSegs = ['', '', `1`];
			wrapper = mount(
				<C
					isOpen={isOpen}
					toggle={toggle}
					create={create}
					entity={entity}
					data={test_algs}
					algorithms={test_algs}
					toolchains={test_tcs}
					nameOrVersion={nameOrVersion}
					copyObj={copyObj}
				/>
			);

			expect(wrapper.state('numSegs')).to.equal(3);
			expect(wrapper.state('nameSegs')).to.deep.equal(newNameSegs);
			const inputs = wrapper.find('input');
			expect(inputs).to.have.length(3);
			expect(inputs.get(0).props.value).to.equal(newNameSegs[0]);
			expect(inputs.get(0).props.disabled).to.equal(false);
			expect(inputs.get(1).props.value).to.equal(newNameSegs[1]);
			expect(inputs.get(1).props.disabled).to.equal(false);
			expect(inputs.get(2).props.value).to.equal(newNameSegs[2]);
			expect(inputs.get(2).props.disabled).to.equal(true);
		});

		it(`properly handles copying`, () => {
			const nameOrVersion = true;
			const copyObj = test_algs[0];
			const oldNameSegs = copyObj.name.split('/');
			const copyVersion = Number.parseInt(oldNameSegs.slice(-1)[0]);
			const newNameSegs = [...oldNameSegs.slice(0, -1), `1`];
			wrapper = mount(
				<C
					isOpen={isOpen}
					toggle={toggle}
					create={create}
					entity={entity}
					data={test_dbs}
					algorithms={test_algs}
					toolchains={test_tcs}
					nameOrVersion={nameOrVersion}
					copyObj={copyObj}
				/>
			);

			expect(wrapper.state('numSegs')).to.equal(3);
			expect(wrapper.state('nameSegs')).to.deep.equal(newNameSegs);
			const inputs = wrapper.find('input');
			expect(inputs).to.have.length(3);
			expect(inputs.get(0).props.value).to.equal(newNameSegs[0]);
			expect(inputs.get(0).props.disabled).to.equal(false);
			expect(inputs.get(1).props.value).to.equal(newNameSegs[1]);
			expect(inputs.get(1).props.disabled).to.equal(false);
			expect(inputs.get(2).props.value).to.equal(newNameSegs[2]);
			expect(inputs.get(2).props.disabled).to.equal(true);
		});

		it(`properly handles creating a new version`, () => {
			const nameOrVersion = false;
			const copyObj = test_algs[0];
			const oldNameSegs = copyObj.name.split('/');
			const copyVersion = Number.parseInt(oldNameSegs.slice(-1)[0]);
			const newNameSegs = [...oldNameSegs.slice(0, -1), `${ copyVersion + 1 }`];
			wrapper = mount(
				<C
					isOpen={isOpen}
					toggle={toggle}
					create={create}
					entity={entity}
					data={test_dbs}
					algorithms={test_algs}
					toolchains={test_tcs}
					nameOrVersion={nameOrVersion}
					copyObj={copyObj}
				/>
			);

			expect(wrapper.state('numSegs')).to.equal(3);
			expect(wrapper.state('nameSegs')).to.deep.equal(newNameSegs);
			const inputs = wrapper.find('input');
			expect(inputs).to.have.length(3);
			expect(inputs.get(0).props.value).to.equal(newNameSegs[0]);
			expect(inputs.get(0).props.disabled).to.equal(true);
			expect(inputs.get(1).props.value).to.equal(newNameSegs[1]);
			expect(inputs.get(1).props.disabled).to.equal(true);
			expect(inputs.get(2).props.value).to.equal(newNameSegs[2]);
			expect(inputs.get(2).props.disabled).to.equal(true);
		});
	});

	describe('for experiments', () => {
		const entity = 'experiment';
		it(`properly handles creating a new object`, () => {
			const nameOrVersion = true;
			const copyObj = undefined;
			const newNameSegs = ['', '', '', '', ''];
			wrapper = mount(
				<C
					isOpen={isOpen}
					toggle={toggle}
					create={create}
					entity={entity}
					data={test_exps}
					algorithms={test_algs}
					toolchains={test_tcs}
					nameOrVersion={nameOrVersion}
					copyObj={copyObj}
				/>
			);

			expect(wrapper.state('numSegs')).to.equal(5);
			expect(wrapper.state('nameSegs')).to.deep.equal(newNameSegs);
			const inputs = wrapper.find('input');
			const select = wrapper.find('select');
			expect(inputs).to.have.length(2);
			expect(inputs.get(0).props.value).to.equal(newNameSegs[0]);
			expect(inputs.get(0).props.disabled).to.be.undefined;
			expect(select.get(0).props.value).to.equal('');
			expect(select.get(0).props.disabled).to.be.undefined;
			expect(inputs.get(1).props.value).to.equal(newNameSegs[4]);
			expect(inputs.get(1).props.disabled).to.be.undefined;
		});

		it(`properly handles copying`, () => {
			const nameOrVersion = true;
			const copyObj = test_exps[0];
			const oldNameSegs = copyObj.name.split('/');
			const newNameSegs = [...oldNameSegs];
			wrapper = mount(
				<C
					isOpen={isOpen}
					toggle={toggle}
					create={create}
					entity={entity}
					data={test_exps}
					algorithms={test_algs}
					toolchains={test_tcs}
					nameOrVersion={nameOrVersion}
					copyObj={copyObj}
				/>
			);

			expect(wrapper.state('numSegs')).to.equal(5);
			expect(wrapper.state('nameSegs')).to.deep.equal(newNameSegs);
			const inputs = wrapper.find('input');
			const select = wrapper.find('select');
			expect(inputs).to.have.length(2);
			expect(inputs.get(0).props.value).to.equal(newNameSegs[0]);
			expect(inputs.get(0).props.disabled).to.be.undefined;
			expect(select.get(0).props.value).to.equal(newNameSegs.slice(1, 4).join('/'));
			expect(select.get(0).props.disabled).to.be.undefined;
			expect(inputs.get(1).props.value).to.equal(newNameSegs[4]);
			expect(inputs.get(1).props.disabled).to.be.undefined;
		});
	});
});
