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

import { getValidDataformatObj as getValidObj } from '@helpers/beat';
import { DataformatEditor as C } from '.';

import testDfs from '@test/test_dfs.json';

describe('<DataformatEditor />', () => {
	let wrapper;

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

	describe('accepts', () => {
		const dfs = [
			{
				name: 'test/df/1',
				contents: {
					'#description': '',
					'field_1': 'string',
				}
			}
		].concat(testDfs.map(df => getValidObj(df)));

		dfs.forEach(function(df){
			const saveFunc = () => {};
			const updateFunc = () => {};
			it(`${ df.name }`, () => {
				wrapper = mount(
					<C
						data={df}
						dataformats={dfs}
						saveFunc={saveFunc}
						updateFunc={updateFunc}
					/>
				);

				expect(wrapper).to.have.props(
					['data', 'dataformats', 'saveFunc', 'updateFunc']
				).deep.equal(
					[df, dfs, saveFunc, updateFunc]
				);
			});
		});
	});

	describe('creates', () => {
		it('system/integer/1', () => {
			const dfName = 'system/integer/1';
			const saveFunc = sinon.spy();
			const _updateFunc = (obj) => {
				wrapper.setProps && wrapper.setProps({ data: obj });
			};
			const updateFunc = sinon.spy(_updateFunc);
			wrapper = mount(
				<C
					data={getValidObj({name: dfName, contents: {}})}
					dataformats={testDfs.filter(d => d.name !== dfName)}
					saveFunc={saveFunc}
					updateFunc={updateFunc}
				/>
			);

			expect(wrapper).to.have.props(
				['data', 'dataformats', 'saveFunc', 'updateFunc']
			);

			expect(wrapper.props().data).to.have.property('name', dfName);

			wrapper.find('input[name="description"]').simulate('change', { target: { value: 'Single (32 bits) integer value'}});
			expect(wrapper.props().data.contents).to.have.property('#description', 'Single (32 bits) integer value');
			expect(updateFunc.callCount).to.equal(1);

			wrapper.find('button.btn-success').simulate('click');
			expect(updateFunc.callCount).to.equal(2);
			wrapper.find('CacheInput[placeholder="Name..."]').prop('onChange')( { target: { value: 'value' }});
			expect(updateFunc.callCount).to.equal(3);

			wrapper.find('select').simulate('change', { target: { value: 'int32' }});
			expect(updateFunc.callCount).to.equal(4);
			expect(wrapper.props().data.contents).to.have.property('value', 'int32');

			expect(wrapper.props().data).to.deep.equal({
				'name': 'system/integer/1',
				'contents': {
					'#description': 'Single (32 bits) integer value',
					'value': 'int32'
				}
			});
		});

		it('system/array_1d_text/1', () => {
			const dfName = 'system/array_1d_text/1';
			const saveFunc = sinon.spy();
			const _updateFunc = (obj) => {
				wrapper.setProps && wrapper.setProps({ data: obj });
			};
			const updateFunc = sinon.spy(_updateFunc);
			wrapper = mount(
				<C
					data={getValidObj({name: dfName, contents: {}})}
					dataformats={testDfs.filter(d => d.name !== dfName)}
					saveFunc={saveFunc}
					updateFunc={updateFunc}
				/>
			);

			expect(wrapper).to.have.props(
				['data', 'dataformats', 'saveFunc']
			);

			expect(wrapper.props().data).to.have.property('name', dfName);

			wrapper.find('button.btn-success').simulate('click');
			wrapper.find('CacheInput[placeholder="Name..."]').prop('onChange')( { target: { value: 'text' }});

			wrapper.find('select').simulate('change', { target: { value: 'array' }});
			expect(wrapper.props().data.contents).to.have.deep.property('text', [0, 'string']);

			expect(wrapper.props().data).to.deep.equal({
				'name': 'system/array_1d_text/1',
				'contents': {
					'#description': '',
					'text': [
						0,
						'string'
					]
				}
			});
		});

		it('system/array_2d_floats/1', () => {
			const dfName = 'system/array_2d_floats/1';
			const saveFunc = sinon.spy();
			const _updateFunc = (obj) => {
				wrapper.setProps && wrapper.setProps({ data: obj });
			};
			const updateFunc = sinon.spy(_updateFunc);
			wrapper = mount(
				<C
					data={getValidObj({name: dfName, contents: {}})}
					dataformats={testDfs.filter(d => d.name !== dfName)}
					saveFunc={saveFunc}
					updateFunc={updateFunc}
				/>
			);

			expect(wrapper).to.have.props(
				['data', 'dataformats', 'saveFunc']
			);

			expect(wrapper.props().data).to.have.property('name', dfName);

			wrapper.find('input[name="description"]').simulate('change', { target: { value: 'Basic format containing a two-dimensional array of float values'}});
			expect(wrapper.props().data.contents).to.have.property('#description', 'Basic format containing a two-dimensional array of float values');

			wrapper.find('button.btn-success').simulate('click');
			wrapper.find('CacheInput[placeholder="Name..."]').prop('onChange')( { target: { value: 'value' }});

			wrapper.find('select').simulate('change', { target: { value: 'array' }});
			wrapper.find('input[type="number"][min="1"]').simulate('change', { target: { value: '2' }});
			wrapper.find('select').at(1).simulate('change', { target: { value: 'float64' }});

			expect(wrapper.props().data.contents).to.have.deep.property('value', [0, 0, 'float64']);

			expect(wrapper.props().data).to.deep.equal({
				'name': 'system/array_2d_floats/1',
				'contents': {
					'#description': 'Basic format containing a two-dimensional array of float values',
					'value': [
						0,
						0,
						'float64'
					]
				}
			});
		});

		it('plot/bar/1', () => {
			const dfName = 'plot/bar/1';
			const saveFunc = sinon.spy();
			const _updateFunc = (obj) => {
				wrapper.setProps && wrapper.setProps({ data: obj });
			};
			const updateFunc = sinon.spy(_updateFunc);
			wrapper = mount(
				<C
					data={getValidObj({name: dfName, contents: {}})}
					dataformats={testDfs.filter(d => d.name !== dfName)}
					saveFunc={saveFunc}
					updateFunc={updateFunc}
				/>
			);

			expect(wrapper).to.have.props(
				['data', 'dataformats', 'saveFunc']
			);

			expect(wrapper.props().data).to.have.property('name', dfName);

			wrapper.find('input[name="description"]').simulate('change', { target: { value: 'Array of bar plots'}});
			expect(wrapper.props().data.contents).to.have.property('#description', 'Array of bar plots');

			// 'data' field
			wrapper.find('.dfLevel button.btn-success').simulate('click');
			wrapper.find('.dfLevel .field0 CacheInput[placeholder="Name..."]').prop('onChange')( { target: { value: 'data' }});
			wrapper.find('.dfLevel .field0 select').simulate('change', { target: { value: 'array' }});
			wrapper.find('.dfLevel .field0 select.subtype').simulate('change', { target: { value: 'object' }});
			expect(wrapper.props().data.contents).to.have.deep.property('data', [0, {}]);

			// 'label' subfield
			wrapper.find('.dfLevel .field0 .dfLevel button.btn-success').simulate('click');
			wrapper.find('.dfLevel .field0 .dfLevel .field0 CacheInput[placeholder="Name..."]').prop('onChange')( { target: { value: 'label' }});
			wrapper.find('.dfLevel .field0 .dfLevel .field0 select').simulate('change', { target: { value: 'string' }});
			expect(wrapper.props().data.contents.data[1]).to.have.deep.property('label', 'string');

			// 'x' subfield
			wrapper.find('.dfLevel .field0 .dfLevel button.btn-success').simulate('click');
			wrapper.find('.dfLevel .field0 .dfLevel .field1 CacheInput[placeholder="Name..."]').prop('onChange')( { target: { value: 'x' }});
			wrapper.find('.dfLevel .field0 .dfLevel .field1 select').simulate('change', { target: { value: 'array' }});
			wrapper.find('.dfLevel .field0 .dfLevel .field1 select.subtype').simulate('change', { target: { value: 'float64' }});
			expect(wrapper.props().data.contents.data[1]).to.have.deep.property('x', [0, 'float64']);

			// 'y' subfield
			wrapper.find('.dfLevel .field0 .dfLevel button.btn-success').simulate('click');
			wrapper.find('.dfLevel .field0 .dfLevel .field2 CacheInput[placeholder="Name..."]').prop('onChange')( { target: { value: 'y' }});
			wrapper.find('.dfLevel .field0 .dfLevel .field2 select').simulate('change', { target: { value: 'array' }});
			wrapper.find('.dfLevel .field0 .dfLevel .field2 select.subtype').simulate('change', { target: { value: 'float64' }});
			expect(wrapper.props().data.contents.data[1]).to.have.deep.property('y', [0, 'float64']);


			expect(wrapper.props().data).to.deep.equal({
				'name': 'plot/bar/1',
				'contents': {
					'#description': 'Array of bar plots',
					'data': [
						0,
						{
							'label': 'string',
							'x': [
								0,
								'float64'
							],
							'y': [
								0,
								'float64'
							]
						}
					]
				}
			});
		});
	});
});
