/*!
 * 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 RestAPIUtil from 'nfvo-utils/RestAPIUtil.js';
import Configuration from 'sdc-app/config/Configuration.js';
import {actionTypes, enums} from './FlowsConstants.js';
import SequenceDiagramModelHelper from './SequenceDiagramModelHelper.js';


function baseUrl(serviceId, artifactId = '') {
	const restATTPrefix = Configuration.get('restATTPrefix');
	return `${restATTPrefix}/v1/catalog/services/${serviceId}/artifacts/${artifactId}`;
}

function encodeDataToBase64(dataAsString) {
	return window.btoa(dataAsString);
}

function decodeDataToBase64(encodedData) {
	return window.atob(encodedData);
}

function encodeContent(flowData) {
	let data = {
		VERSION: {
			major: 1,
			minor: 0
		},
		description: flowData.description,
		sequenceDiagramModel: flowData.sequenceDiagramModel
	};

	return encodeDataToBase64(JSON.stringify(data));
}

function decodeContent(base64Contents) {
	let description, sequenceDiagramModel;
	let payload = JSON.parse(decodeDataToBase64(base64Contents));

	if (payload.VERSION === undefined) {
		description = payload.description || 'Please, provide description...';
		sequenceDiagramModel = payload.data || payload;
		sequenceDiagramModel = sequenceDiagramModel.model || sequenceDiagramModel;

	}
	else if (payload.VERSION.major === 1) {
		description = payload.description;
		sequenceDiagramModel = payload.sequenceDiagramModel;
	}

	return {
		description,
		sequenceDiagramModel
	};
}

function createOrUpdate(flowData) {
	let createOrUpdateRequest = {
		payloadData: encodeContent(flowData),
		artifactLabel: flowData.artifactLabel || flowData.artifactName,
		artifactName: flowData.artifactName,
		artifactType: flowData.artifactType,
		artifactGroupType: enums.INFORMATIONAL,
		description: flowData.description
	};

	return RestAPIUtil.post(
		baseUrl(flowData.serviceID, flowData.uniqueId),
		createOrUpdateRequest,
		{md5: true}
	);
}

const FlowsActions = Object.freeze({

	fetchFlowArtifacts(dispatch, {artifacts, diagramType, participants, serviceID, readonly}) {
		let results = [];
		if (!Object.keys(artifacts).length) {
			dispatch({type: actionTypes.FLOW_LIST_LOADED, results, participants, serviceID, diagramType, readonly});
			if (!readonly) {
				FlowsActions.openFlowDetailsEditor(dispatch);
			}
		}
		else {
			Object.keys(artifacts).forEach(artifact => results.push({
				artifactType: diagramType,
				participants,
				serviceID,
				...artifacts[artifact]
			}));
			dispatch({type: actionTypes.FLOW_LIST_LOADED, results, participants, serviceID, diagramType, readonly});
		}
	},

	fetchArtifact(dispatch, {flow}){
		let {serviceID, uniqueId, participants} = flow;
		return RestAPIUtil.fetch(baseUrl(serviceID, uniqueId)).then(response => {

			let {artifactName, base64Contents} = response;
			let {sequenceDiagramModel, ...other} = decodeContent(base64Contents);

			if (!sequenceDiagramModel) {
				sequenceDiagramModel = SequenceDiagramModelHelper.createModel({
					id: uniqueId,
					name: artifactName,
					lifelines: participants
				});
			}
			else {
				sequenceDiagramModel = SequenceDiagramModelHelper.updateModel(sequenceDiagramModel, {
					name: artifactName,
					lifelines: participants
				});
			}

			flow = {
				...flow,
				...other,
				uniqueId,
				artifactName,
				sequenceDiagramModel
			};

			dispatch({type: actionTypes.ARTIFACT_LOADED, flow});
			FlowsActions.openFlowDiagramEditor(dispatch, {flow});
		});
	},

	createOrUpdateFlow(dispatch, {flow}, isNew) {
		if (!isNew && flow.sequenceDiagramModel) {
			flow.sequenceDiagramModel = SequenceDiagramModelHelper.updateModel(flow.sequenceDiagramModel, {
				name: flow.artifactName
			});
		}
		return createOrUpdate(flow).then(response => {
			let {uniqueId, artifactLabel} = response;
			flow = {...flow, uniqueId, artifactLabel};
			if (isNew) {
				flow.sequenceDiagramModel = SequenceDiagramModelHelper.createModel({id: uniqueId, name: flow.artifactName});
			}
			dispatch({type: actionTypes.ADD_OR_UPDATE_FLOW, flow});
		});
	},

	deleteFlow(dispatch, {flow}) {
		return RestAPIUtil.destroy(baseUrl(flow.serviceID, flow.uniqueId)).then(() => dispatch({
			type: actionTypes.DELETE_FLOW,
			flow
		}));
	},

	openFlowDetailsEditor(dispatch, flow) {
		dispatch({type: actionTypes.OPEN_FLOW_DETAILS_EDITOR, flow});
	},

	closeFlowDetailsEditor(dispatch) {
		dispatch({type: actionTypes.CLOSE_FLOW_DETAILS_EDITOR});
	},

	openFlowDiagramEditor(dispatch, {flow}) {
		dispatch({type: actionTypes.OPEN_FLOW_DIAGRAM_EDITOR, flow});
	},

	closeFlowDiagramEditor(dispatch) {
		dispatch({type: actionTypes.CLOSE_FLOW_DIAGRAM_EDITOR});
	},

	reset(dispatch) {
		dispatch({type: actionTypes.RESET});
	}
});

export default FlowsActions;
