/*!
 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

import deepFreeze from 'deep-freeze';
import mockRest from 'test-utils/MockRest.js';
import store from 'sdc-app/AppStore.js';
import FlowsActions from 'sdc-app/flows/FlowsActions.js';
import {enums} from 'sdc-app/flows/FlowsConstants.js';

import {
	FlowCreateFactory,
	FlowPostRequestFactory,
	FlowPostResponseFactory,
	FlowFetchRequestFactory,
	FlowFetchResponseFactory,
	FlowDeleteRequestFactory,
 	FlowUpdateRequestFactory } from 'test-utils/factories/flows/FlowsFactories.js';

import {buildFromExistingObject} from 'test-utils/Util.js';

const NEW_FLOW = true;

let assertFlowDataAfterCreateFetchAndUpdate = (data) => {
	let {flowList, serviceID, diagramType} = store.getState().flows;
	expect(serviceID).toBe(data.serviceID);
	expect(diagramType).toBe(data.artifactType);
	let uniqueId = data.uniqueId || `${data.serviceID}.${data.artifactName}`;
	let index = flowList.findIndex(flow => flow.uniqueId === uniqueId);
	expect(index).not.toBe(-1);
};

describe('Workflows and Management Flows Module Tests:', function () {


	it('empty artifact should open flow creation modal', () => {

		const artifacts = {};

		deepFreeze(store.getState());
		deepFreeze(artifacts);
		FlowsActions.fetchFlowArtifacts(store.dispatch, {
			artifacts,
			diagramType: enums.WORKFLOW,
			participants: [],
			serviceID: '1234'
		});
		let state = store.getState();
		expect(state.flows.isDisplayModal).toBe(true);
		expect(state.flows.isModalInEditMode).toBe(false);
	});

	it('Close flow details editor modal', () => {
		deepFreeze(store.getState());
		FlowsActions.closeFlowDetailsEditor(store.dispatch);
		let state = store.getState();
		expect(state.flows.isDisplayModal).toBe(false);
		expect(state.flows.isModalInEditMode).toBe(false);
	});

	it('Get Flows List from loaded artifact', () => {

		deepFreeze(store.getState());

		const artifacts = {
			'test1': FlowPostResponseFactory.build({artifactName: 'test1'}),
			'kukuriku': FlowPostResponseFactory.build({
				'artifactType': 'PUPPET',
				'artifactName': 'kukuriku',
			}),
			'test3': FlowPostResponseFactory.build({artifactName: 'test3'})
		};

		const artifactsArray = Object.keys(artifacts).map(artifact => artifact);

		deepFreeze(artifacts);

		deepFreeze(store.getState());

		let actionData = {
			artifacts,
			diagramType: enums.WORKFLOW,
			participants: [],
			serviceID: '1234'
		};
		FlowsActions.fetchFlowArtifacts(store.dispatch, actionData);

		let state = store.getState();
		expect(state.flows.isDisplayModal).toBe(false);
		expect(state.flows.isModalInEditMode).toBe(false);
		expect(state.flows.flowList.length).toEqual(artifactsArray.length);
		expect(state.flows.flowParticipants).toEqual(actionData.participants);
		expect(state.flows.serviceID).toBe(actionData.serviceID);
		expect(state.flows.diagramType).toBe(actionData.diagramType);

	});


	it('Add New Flow', () => {

		deepFreeze(store.getState());

		const flowCreateData = FlowCreateFactory.build();
		let expectedDataToBeSentInTheRequest = buildFromExistingObject(FlowPostRequestFactory, flowCreateData);

		mockRest.addHandler('post', ({data, baseUrl, options}) => {
			expect(baseUrl).toBe(`/sdc1/feProxy/rest/v1/catalog/services/${flowCreateData.serviceID}/artifacts/`);
			expect(data.artifactLabel).toBe(expectedDataToBeSentInTheRequest.artifactLabel);
			expect(data.artifactName).toBe(expectedDataToBeSentInTheRequest.artifactName);
			expect(data.artifactType).toBe(expectedDataToBeSentInTheRequest.artifactType);
			expect(data.description).toBe(expectedDataToBeSentInTheRequest.description);
			expect(data.payloadData).toBe(expectedDataToBeSentInTheRequest.payloadData);
			expect(options.md5).toBe(true);
			return buildFromExistingObject(FlowPostResponseFactory, expectedDataToBeSentInTheRequest);
		});

		return FlowsActions.createOrUpdateFlow(store.dispatch, {flow: flowCreateData}, NEW_FLOW).then(() => {
			assertFlowDataAfterCreateFetchAndUpdate(flowCreateData);
		});

		
	});

	it('Fetch Flow', () => {

		deepFreeze(store.getState());

		const flowFetchData = FlowFetchRequestFactory.build();

		mockRest.addHandler('fetch', ({baseUrl}) => {
			//sdc1/feProxy/rest/v1/catalog/services/338d75f0-aec8-4eb4-89c9-8733fcd9bf3b/artifacts/338d75f0-aec8-4eb4-89c9-8733fcd9bf3b.zizizi
			expect(baseUrl).toBe(`/sdc1/feProxy/rest/v1/catalog/services/${flowFetchData.serviceID}/artifacts/${flowFetchData.uniqueId}`);
			return buildFromExistingObject(FlowFetchResponseFactory, flowFetchData);
		});

		return FlowsActions.fetchArtifact(store.dispatch, {flow: flowFetchData}).then(() => {
			assertFlowDataAfterCreateFetchAndUpdate(flowFetchData);
		});
	});

	it('Update Existing Flow', () => {

		deepFreeze(store.getState());
		const flowUpdateData = FlowUpdateRequestFactory.build();

		mockRest.addHandler('post', ({baseUrl}) => {
			expect(baseUrl).toBe(`/sdc1/feProxy/rest/v1/catalog/services/${flowUpdateData.serviceID}/artifacts/${flowUpdateData.uniqueId}`);

			return buildFromExistingObject(FlowPostResponseFactory, flowUpdateData);
		});

		return FlowsActions.createOrUpdateFlow(store.dispatch, {flow: flowUpdateData}, !NEW_FLOW).then(() => {
			assertFlowDataAfterCreateFetchAndUpdate(flowUpdateData);
		});

	});

	it('Delete Flow', () => {

		deepFreeze(store.getState());

		const flowDeleteData = FlowDeleteRequestFactory.build();

		mockRest.addHandler('destroy', ({baseUrl}) => {
			expect(baseUrl).toBe(`/sdc1/feProxy/rest/v1/catalog/services/${flowDeleteData.serviceID}/artifacts/${flowDeleteData.uniqueId}`);
			return {};
		});

		return FlowsActions.deleteFlow(store.dispatch, {flow: flowDeleteData}).then(() => {
			let {flowList} = store.getState().flows;
			let index = flowList.findIndex(flow => flow.uniqueId === flowDeleteData.uniqueId);
			expect(index).toBe(-1);
		});
	});
});
