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

import C from './ToolchainModal.jsx';

// sleep for a bit, to wait for async things
const sleep = (ms) => {
	return new Promise(resolve => setTimeout(resolve, ms));
};

describe('<ToolchainModal />', function () {
	this.timeout(10000);

	let wrapper;

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

	const testBlockData = {
		name: 'block1',
		inputs: [
			'input1',
		],
		outputs: [
			'output1',
		],
		synchronized_channel: 'dataset1',
	};

	const testBlockData2 = {
		name: 'block1',
		inputs: [
			'input0',
			'input1',
		],
		outputs: [
			'output1',
		],
		synchronized_channel: 'dataset1',
	};

	const testChannels = { 'dataset1': '#880000' };

	const testBlockNames = ['block1'];

	it('accepts the test data with the right props', () => {
		wrapper = mount(
			<C
				active={true}
				data={testBlockData}
				blockNames={testBlockNames}
				possibleChannels={testChannels}
				toggle={() => {}}
				deleteBlock={() => {}}
				updateBlockData={() => {}}
				createAlgorithmFromBlock={() => {}}
			/>
		);
		expect(wrapper).to.have.props([
			'active',
			'data',
			'blockNames',
			'possibleChannels',
			'toggle',
			'deleteBlock',
			'updateBlockData',
			'createAlgorithmFromBlock',
		]);
	});

	it('lets you change the name to another valid name', async () => {
		const newBlockName = 'block2';
		wrapper = mount(
			<C
				active={true}
				data={testBlockData}
				blockNames={testBlockNames}
				possibleChannels={testChannels}
				toggle={() => {}}
				deleteBlock={() => {}}
				updateBlockData={() => {}}
				createAlgorithmFromBlock={() => {}}
			/>
		);
		wrapper.find('input#tcModalInitFocus').prop('onChange')( { target: { value: newBlockName }});
		wrapper.update();
		await sleep(300);
		wrapper.update();
		expect(wrapper.exists('.input-group-append .text-danger')).to.equal(false);
	});

	it('doesnt let you change the name to a valid name with a dash ("-") in it', async () => {
		const newBlockName = 'block-2';
		wrapper = mount(
			<C
				active={true}
				data={testBlockData}
				blockNames={testBlockNames}
				possibleChannels={testChannels}
				toggle={() => {}}
				deleteBlock={() => {}}
				updateBlockData={() => {}}
				createAlgorithmFromBlock={() => {}}
			/>
		);
		wrapper.find('input#tcModalInitFocus').prop('onChange')( { target: { value: newBlockName }});
		wrapper.update();
		await sleep(300);
		wrapper.update();
		expect(wrapper.exists('.input-group-append .text-danger')).to.equal(true);
	});

	it('lets you switch the names of inputs (test 1)', async () => {
		const newBlockName = 'block';
		wrapper = mount(
			<C
				active={true}
				data={testBlockData2}
				blockNames={testBlockNames}
				possibleChannels={testChannels}
				toggle={() => {}}
				deleteBlock={() => {}}
				updateBlockData={() => {}}
				createAlgorithmFromBlock={() => {}}
			/>
		);
		wrapper.find('input[value="input0"]').prop('onChange')( { target: { value: 'input1' }});
		wrapper.update();
		await sleep(1000);
		wrapper.find('input[value="input1"]').at(1).prop('onChange')( { target: { value: 'input0' }});
		wrapper.update();
		await sleep(1000);
		wrapper.update();
		expect(wrapper.state('cache')).to.have.deep.property('inputs', [
			{ action: 'change', name: 'input1', original: 'input0' },
			{ action: 'change', name: 'input0', original: 'input1' },
		]);
	});

	it('lets you switch the names of inputs (test 2)', async () => {
		const newBlockName = 'block';
		wrapper = mount(
			<C
				active={true}
				data={testBlockData2}
				blockNames={testBlockNames}
				possibleChannels={testChannels}
				toggle={() => {}}
				deleteBlock={() => {}}
				updateBlockData={() => {}}
				createAlgorithmFromBlock={() => {}}
			/>
		);
		wrapper.find('input[value="input1"]').prop('onChange')( { target: { value: 'input0' }});
		wrapper.update();
		await sleep(1000);
		wrapper.find('input[value="input0"]').at(0).prop('onChange')( { target: { value: 'input1' }});
		wrapper.update();
		await sleep(1000);
		wrapper.update();
		expect(wrapper.state('cache')).to.have.deep.property('inputs', [
			{ action: 'change', name: 'input1', original: 'input0' },
			{ action: 'change', name: 'input0', original: 'input1' },
		]);
	});

	it('doesnt change the name of multiple inputs/outputs at a time', async () => {
		const newBlockName = 'block';
		wrapper = mount(
			<C
				active={true}
				data={testBlockData2}
				blockNames={testBlockNames}
				possibleChannels={testChannels}
				toggle={() => {}}
				deleteBlock={() => {}}
				updateBlockData={() => {}}
				createAlgorithmFromBlock={() => {}}
			/>
		);

		wrapper.find('button.btn.btn-secondary').at(1).simulate('click');;
		wrapper.update();
		expect(wrapper.state('cache').inputs[2]).to.deep.equal({ action: 'add', name: 'input', original: 'input' });
		wrapper.find('CacheInput[value="input"]').prop('onChange')( { target: { value: 'test0' }});
		wrapper.update();
		wrapper.find('button.btn.btn-secondary').at(1).simulate('click');;
		wrapper.update();
		expect(wrapper.state('cache').inputs[3]).to.deep.equal({ action: 'add', name: 'input2', original: 'input2' });
		wrapper.find('CacheInput[value="input2"]').prop('onChange')( { target: { value: 'test1' }});
		wrapper.update();
		expect(wrapper.state('cache').inputs[2]).to.deep.equal({ action: 'add', name: 'test0', original: 'input' });
		expect(wrapper.state('cache').inputs[3]).to.deep.equal({ action: 'add', name: 'test1', original: 'input2' });
	});
});
