/*!
 * 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;