/**
 * Created by rockyl on 2019-09-19.
 */
import Vue from "vue"
import JSZip from "jszip"
import {editorApi, projectApi} from "../../api"
import path from "path"
import generateUUID from "uuid/v4"
import {flattenViews, getCmpByUUID, getCmpProps} from '../../utils/common'
import {
	assetScheme,
	clonePureObj, deleteAssetsDepConfig,
	deleteDesignConfig,
	findProcess,
	getMockServeEnabled,
	saveAs,
	traverseViewNode, zipViewFile
} from "../../utils"
import {template} from "../../template"
import {packAssetsGroups} from "../../utils/assets-pack"
import {addBehavior, deleteProcessMeta,} from "./behavior"

import db from "../../utils/db-storage"
import {preprocess} from "../../views/Preview/preview-preprocess"
import {packageStore} from "./package"
import {toZeroing} from "psd-parse-web"
import {arrayFind} from "element-ui/src/utils/util";
import {uploadFiles} from "./editor";
import events from "@/global-events.js"

import zlib from 'zlib';

const storeName = 'project';
const psStoreName = 'pack-history';

const defaultOptions = {
	behaviorEditor: 'builtin',
	pageTitle: 'no title',
	entrySceneView: '',
	loadingView: '',
	lazyLoadWait: 1000,
	containerId: 'game-container',
	designWidth: 750,
	designHeight: 1334,
	frameRate: 60,
	scaleMode: 'fixedWidth',
	rendererType: 'webgl',
	tpl: template,
	env: [
		{name: 'appID', value: ''},
		{name: 'projectID', value: ''},
	],
	pxEnv: {
		dev: "",
		test: "",
		prod: "",
	}
};

const OPERATE_MAX_LENGTH = 200; // 撤销重做栈最大值

let nodeUUidCatch = null;


export const projectStore = {
	modules: {
		package: packageStore,
	},
	state: {
		id: '',
		name: '',
		creator: '',
		operator: '',
		operators: '',
		update_time: '',
		remark: '',
		data: {
			options: {},
			views: [],
			assets: [],
			dataMapping: [],
			processes: [],
			customs: [],
			mock: [],
			dependencies: {},
		},
		mockServeEnabled: false,
		activeComponent: {},
		activeComponentCopy: {}, // 当前选中节点的镜像，用来处理拖拽时数据变化频繁的问题
		activeIdList: [],
		dragUUID: '',
		dirty: false,
		operateStack: [],
		stackIndex: 0,
		activeView: null,
	},
	mutations: {
		setDirty(state, dirty = true) {
			state.dirty = dirty;
		},
		makeProjectDirty() {
		},
		resetProjectData(state, data) {
			state.data = data;
		},
		updateProjectUpdateTime(state, {time, dirty = true}) {
			state.update_time = time;

			if (dirty) {
				this.commit('makeProjectDirty');
			}
		},
		updateProject(state, project) {
			const {id, name, creator, data, operators, operator, update_time, remark} = project;
			state.id = id;
			state.name = name;
			state.creator = creator;
			state.operator = operator;
			state.operators = operators || creator; //兼容未保存的本地存储
			state.update_time = update_time;
			state.remark = remark;

			const localData = state.data;
			if (data) {
				const {views, assets, dataMapping, processes, options, customs, mock, dependencies} = typeof data === 'string' ? JSON.parse(data) : data;

				Vue.set(localData, 'options', options || getDefaultOptions());
				Vue.set(localData, 'views', views || []);
				Vue.set(localData, 'assets', assets || []);
				Vue.set(localData, 'dataMapping', dataMapping || []);
				Vue.set(localData, 'processes', processes || []);
				Vue.set(localData, 'customs', customs || []);
				Vue.set(localData, 'mock', mock || []);
				Vue.set(localData, 'dependencies', dependencies || {});
			} else {
				Vue.set(localData, 'options', getDefaultOptions());
				Vue.set(localData, 'views', []);
				Vue.set(localData, 'assets', []);
				Vue.set(localData, 'dataMapping', []);
				Vue.set(localData, 'processes', []);
				Vue.set(localData, 'customs', []);
				Vue.set(localData, 'mock', []);
				Vue.set(localData, 'dependencies', {});
			}

			if (!localData.options.pxEnv) {
				localData.options.pxEnv = getDefaultOptions().pxEnv;
			}

			if (!localData.options.behaviorEditor) {
				localData.options.behaviorEditor = 'builtin';
			}

			this.dispatch('fillLastVersion');
			this.commit('updateAssetDep');


			state.mockServeEnabled = getMockServeEnabled(id);
			updateMock(localData.mock);
		},
		updateRemark(state, remark) {
			state.remark = remark;
		},
		updateAssetDep(state) {
			let assets = state.data.assets;
			let explicitDepAssets;

			for (let view of state.data.views) {
				if (!view.implicitDepAssets) {
					Vue.set(view, 'implicitDepAssets', []);
				}
				if (view.explicitDepAssets) {
					view.explicitDepAssets.splice(0);
				} else {
					Vue.set(view, 'explicitDepAssets', []);
				}
				explicitDepAssets = view.explicitDepAssets;
				onHitViewNode(view);
				traverseViewNode(view.children, onHitViewNode);
			}

			function onHitViewNode(node) {
				for (let field in node.properties) {
					let prop = node.properties[field];
					if (prop && typeof prop === 'string' && prop.startsWith(assetScheme) && !prop.includes('${')) {
						let uuid = prop.replace(assetScheme, '');
						let asset = assets.find(asset => asset.uuid === uuid);
						if (asset) {
							if (!explicitDepAssets.includes(asset.uuid)) {
								explicitDepAssets.push(asset.uuid);
							}
						}
					}
				}
			}
		},
		modifyOptions(state, value) {
			state.data.options = value;
		},
		modifyEnv(state, value) {
			state.data.options.env = value;
		},
		modifyProjectx(state, value) {
			state.data.options.pxEnv = value;
		},
		modifyDataMapping(state, value) {
			state.data.dataMapping = value;
		},
		modifyCustoms(state, value) {
			state.data.customs = value;
		},
		modifyProjectDetails(state) {

		},
		modifyDependencies(state, value) {
			state.data.dependencies = value;
		},
		modifyOperators(state, value) {
			state.operators = value;
		},
		/**
		 * 激活组件
		 * @param {*} state
		 * @param {*} item
		 */
		activeComponent(state, item) {
			if (item !== state.activeComponent) {
				state.activeComponent = item || state.activeComponent;
				state.activeComponent.properties = state.activeComponent.properties || {};
				state.activeComponentCopy = _.cloneDeep(state.activeComponent);
			}
		},
		/**
		 * 设置当前视图
		 * @param state
		 * @param view
		 */
		setActiveView(state, view) {
			state.activeView = view;
		},
		/**
		 * 修改当前选中的节点
		 * @param {*} state
		 * @param {*} view
		 */
		modifyActiveView(state, view) {
			if (!view) {
				return;
			}

			let oldView = _.cloneDeep(state.activeComponent || {});
			if (state.operateStack.length) {
				if (state.stackIndex !== 0) {
					// 如果操作栈index有值，说明之前做过撤销/重做
					// 则把操作index之后的数据都丢弃
					state.operateStack = state.operateStack.slice(state.stackIndex);
				}
				let lastOperate = state.operateStack[0];
				// // 上一次的操作和最新一次操作uuid不同，表示发生了不同视图的操作
				// // 需要记录当前视图的原始数据
				if (lastOperate.uuid !== oldView.uuid) {
					state.operateStack.unshift(_.cloneDeep(oldView));
				}
			} else {
				// 如果操作栈中是空的，说明从来没有操作
				// 则在开始插入数据的时候，额外插入一条最原始的数据
				state.operateStack.unshift(_.cloneDeep(oldView));
			}

			state.stackIndex = 0; // 开始编辑的时候，重置操作栈的下标
			let newView = _.merge({}, oldView, view);

			// 如果是scripts和events的修改，直接覆盖 不merge
			if (view.scripts) {
				newView.scripts = _.cloneDeep(view.scripts);
			}
			if (view.events) {
				newView.events = _.cloneDeep(view.events);
			}
			// 修改properties时，做减量操作，判断是否有属性的值被清空
			if (view.properties) {
				newView.properties = _.cloneDeep(view.properties);
				_.forIn(newView.properties, (value, key) => {
					if (value === null || value === undefined) {
						delete newView.properties[key];
					}
				});
			}

			if (view.type) {
				// view.type有值说明修改了节点的类型
				// 如果修改了节点类型，需要删除无用的属性
				let defaultProps = Object.keys(getCmpProps(view.type).props);

				_.forIn(newView.properties, (value, key) => {
					if (defaultProps.indexOf(key) === -1) {
						delete newView.properties[key];
					}
				});
			}

			// 在操作栈中插入最新值
			state.operateStack.unshift(_.cloneDeep(newView));
			// 超过最大保存数就丢弃
			if (state.operateStack.length > OPERATE_MAX_LENGTH) {
				state.operateStack.pop();
			}

			// 将数据更新至当前选中的节点上
			_.forIn(newView, (value, key) => {
				// if (key === 'properties') {
				// horizonCenter和left\right
				// verticalCenter和top\bottom
				// 互斥，只要修改了一项，则把互斥项置空
				// if (value.horizonCenter) {
				// 	delete newView.properties.left;
				// 	delete newView.properties.right;
				// }
				// if (value.verticalCenter) {
				// 	delete newView.properties.top;
				// 	delete newView.properties.bottom;
				// }
				// if (value.left || value.right) {
				// 	delete newView.properties.horizonCenter;
				// }
				// if (value.top || value.bottom) {
				// 	delete newView.properties.verticalCenter;
				// }

				// 如果left\right   top\bottom组合同时存在
				// 则根据数值，计算width height
				// if (newView.properties.left && newView.properties.right) {
				// 	//
				// }
				// if (newView.properties.top && newView.properties.bottom) {

				// }

				// }
				Vue.set(state.activeComponent, key, newView[key]);
			});

			// 同步修改镜像节点
			state.activeComponentCopy = _.cloneDeep(state.activeComponent);
		},
		/**
		 * 修改当前组件镜像的属性
		 * @param {*} state
		 * @param {*} props
		 */
		modifyCopyProperties(state, props) {
			if (!props) {
				return;
			}

			let _prop = _.cloneDeep(state.activeComponentCopy.properties || {});
			_prop = Object.assign({}, _prop, props);
			Vue.set(state.activeComponentCopy, 'properties', _prop);
		},
		/**
		 * assets拖拽
		 * @param state
		 * @param {*} data
		 */
		assetDragStart(state, data) {
			state.dragUUID = data.uuid;
		},
		/**
		 * 重做/撤销
		 * @param {*} state
		 * @param {*} step
		 */
		undoRedo(state, step) {
			let _beforeStack = state.operateStack[state.stackIndex];
			state.stackIndex += step;
			let _afterStack = state.operateStack[state.stackIndex];
			if (_beforeStack.uuid !== _afterStack.uuid) {
				// 如果uuid不一样，说明是不同节点的操作，需要把下标多移动一位
				state.stackIndex += step;
			}
			let _operate = state.operateStack[state.stackIndex];
			if (_operate) {
				let _cmp = getCmpByUUID(_operate.uuid, state.data.views);
				if (_cmp) {
					_.forIn(_operate, (value, key) => {
						_cmp[key] = value;
					});
					// _cmp =  _.cloneDeep(_operate); //_.merge(_cmp, _operate);
					if (_operate.uuid === state.activeComponent.uuid) {
						state.activeComponentCopy = _.cloneDeep(_operate);
						state.activeComponent = _.cloneDeep(_operate);
					}
				}
			}
		},
		modifyProject(state) {

		},
		addNode(state, {node, name, type}) {
			const child = {
				name,
				type,
				properties: {},
				events: {},
				uuid: generateUUID(),
			};
			if (node) {
				if (!node.children) {
					Vue.set(node, 'children', []);
				}
				node.children.push(child);
			} else {
				state.data.views.push(child);
			}
			events.$emit("viewReset")

		},
		importView(state, view) {
			state.data.views.push(view);
			events.$emit("viewReset")

		},
		deleteNode(state, {node, parentNode}) {
			const parentChildren = parentNode.children || parentNode;
			const index = parentChildren.indexOf(node);
			parentChildren.splice(index, 1);
			events.$emit("viewReset")

		},

		copyNode(state, {node, parentNode, copyState}) {
			let _node1 = node;
			//console.log(_node1)
			copyNodeCatch = clonePureObj(_node1)
			//console.log("copyNodeCatch", copyNodeCatch)
			if (copyState == 1) {
				//复制行为
				copyNodeCatch.events
			} else if (copyState == 2) {
				//不复制行为
				console.log(this)
				deleteChildEvent(copyNodeCatch)
			}

			//copy(JSON.stringify(copyNodeCatch))
			function deleteChildEvent(copyNodeCatch) {
				//console.log(123)
				delete copyNodeCatch.events;
				if (copyNodeCatch.children) {
					for (let item of copyNodeCatch.children) {
						deleteChildEvent(item)
					}
				}
			}

			events.$emit("viewReset")

		},


		pasteNode(state, {node, parentNode, pasteState}) {
			let _node1 = copyNodeCatch;
			//console.log(copyNodeCatch);
			if (_node1) {
				let _node = copyBaseRoot(_node1);
				setUUIDForAllChildren(_node);
				if (pasteState == 1) {
					parentNode = parentNode;
				} else {
					parentNode = node;
				}
				if (parentNode) {
					if (!parentNode.children) {
						Vue.set(parentNode, 'children', []);
					}
					parentNode.children.push(_node);
				} else {
					state.data.views.push(_node);
				}
			} else {
				console.warn("请先选择一个节点进行复制")
			}
			events.$emit("viewReset")

		},
		importAssets(state, assets) {
			state.data.assets.push(...assets);
		},
		combineAssets(state, {targetAsset, selectedAssets}) {
			//todo 需要遍历所有节点查找使用并替换
			const assets = state.data.assets;
			let targetAssetUrl = assetScheme + targetAsset.uuid;
			let replaceAssetUrls = [];
			for (let asset of selectedAssets) {
				if (asset !== targetAsset) {
					replaceAssetUrls.push(assetScheme + asset.uuid);
					assets.splice(assets.indexOf(asset), 1);
				}
			}
			traverseViewNode(state.data.views, function (node) {
				let properties = node.properties;
				for (let key in properties) {
					if (properties[key] && replaceAssetUrls.includes(properties[key])) {
						properties[key] = targetAssetUrl;
					}
				}
			});
		},
		addAsset(state, {url, file}) {
			const ext = path.extname(file.name);
			state.data.assets.push({
				name: path.basename(file.name, ext),
				ext,
				url,
				uuid: generateUUID(),
			})
		},
		replaceAsset(state, {uuid, url}) {
			const ext = path.extname(url);
			for (let asset of state.data.assets) {
				if (asset.uuid === uuid) {
					asset.url = url;
					asset.ext = ext;
				}
			}
		},
		deleteAsset(state, uuid) {
			const {assets} = state.data;
			for (let i = 0, li = assets.length; i < li; i++) {
				const asset = state.data.assets[i];
				if (asset.uuid === uuid) {
					assets.splice(i, 1);
					break;
				}
			}
		},
		deleteAllAssets(state) {
			const {assets} = state.data;
			assets.splice(0);
		},
		modifyAsset(state, asset) {

		},

		modifyMocks(state, mocks) {
			state.data.mock = mocks;

			updateMock(mocks);
		},

		setMockServeEnabled(state, enabled) {
			state.mockServeEnabled = enabled;
		},

		modifyViewStore(state, {view, store}) {
			view.store = store;
			this.commit('makeProjectDirty');
		},

		addCmd(state, cmd) {
			Vue.set(state.activeComponent.properties, cmd, '');
			this.commit('makeProjectDirty');
		},

		deleteCmd(state, cmd) {
			Vue.delete(state.activeComponent.properties, cmd);
			this.commit('makeProjectDirty');
		},

		modifyViewDepAssets(state, {view, explicitDepAssets, implicitDepAssets, depCustoms}) {
			view.explicitDepAssets = explicitDepAssets;
			view.implicitDepAssets = implicitDepAssets;
			view.depCustoms = depCustoms;

			this.commit('makeProjectDirty');
		},
		overwriteProcesses(state, {processes}) {
			state.data.processes.splice(0);
			state.data.processes.push(...processes);

			this.commit('makeProjectDirty');
		},
	},
	getters: {
		project(state) {
			const {id, name, creator, data, update_time, operator, operators,} = state;
			let newData = clonePureObj(data);
			//delete newData['dependencies'];
			deleteDesignConfig(newData.processes);
			deleteAssetsDepConfig(newData);
			return {
				id, name, creator, update_time, operator, operators,
				data: JSON.stringify(newData),
			};
		},
		projectRemark(state) {
			return state.remark;
		},
		behaviorEditor(state) {
			return state.data.options.behaviorEditor;
		},
		menuBadge: (state) => (key) => {
			let result = false;
			switch (key) {
				case 'save':
					result = state.dirty;
					break;
			}
			return result;
		},
		options(state) {
			return state.data.options;
		},
		processes(state) {
			return state.data.processes;
		},
		envKeys(state) {
			return state.data.options.env.map(item => item.name);
		},
		/**
		 * 当前激活的组件
		 */
		activeComponent: state => {
			return state.activeComponent;
		},
		activeComponentCopy: state => {
			return state.activeComponentCopy;
		},
		/**
		 * 当前激活的组件ID
		 */
		activeComponentId: state => {
			return (state.activeComponent || {}).uuid;
		},
		/**
		 * 扁平化所有节点
		 */
		componentList: state => {
			// 如果有选中的节点，则展示对应的视图组
			// 否则展示第一个视图组
			let _view = state.data.views.length ? [].concat(state.data.views[0]) : [];
			if (state.activeView) {
				_view = state.data.views.filter(v => v.uuid === state.activeView.data.uuid)
			}

			let result = flattenViews(_.cloneDeep(_view));
			// console.log('componentList', result);
			return result;
		},
		/**
		 * 返回Array格式的views
		 */
		views(state) {
			// 如果有选中的节点，则展示对应的视图组
			// 否则展示第一个视图组
			let _view = [];
			if (state.activeView) {
				_view = state.data.views.filter(v => v.uuid === state.activeView.data.uuid)
			} else {
				_view = state.data.views.length ? [].concat(state.data.views[0]) : [];
			}

			return _view;
		},
		assets(state) {
			return state.data.assets;
		},
		assetDepFlag: state => uuid => {
			return state.data.views.filter(view =>
				view.explicitDepAssets && view.explicitDepAssets.includes(uuid) || view.implicitDepAssets && view.implicitDepAssets.includes(uuid)
			).length > 0 ? 0 : -1;
		},
		customs(state) {
			return state.data.customs;
		},
		getProcess: state => behavior => {
			return arrayFind(state.data.processes, process => process.id === behavior.meta);
		},
		dependencies(state) {
			return state.data.dependencies;
		},
		searchProcess: state => (keyword, searchField) => {
			let result = [];
			let paths = findProcess(state.data.processes, state.package.packages.process, function (process, meta) {
				return meta[searchField] && meta[searchField].includes(keyword)
					|| process.meta.includes(keyword)
					|| (process.alias && process.alias.includes(keyword));
			});
			let entries = paths.map(path => path[0].id);
			traverseViewNode(state.data.views, function (node, parent) {
				for (let eventName in node.events) {
					let event = node.events[eventName];
					for (let behavior of event.behaviors) {
						let index = entries.indexOf(behavior.meta);
						if (index >= 0) {
							let path = paths.splice(index, 1, null)[0];
							if (!path) {
								continue;
							}
							path[0] = {
								process: behavior,
								metaName: path[0].name,
							};
							result.push({
								node,
								path,
							});
						}
					}
				}
			});
			/*for (let path of paths) {
				if (path) {
					result.push({
						path,
					})
				}
			}*/

			return result;
		},
	},
	actions: {
		async saveToLocal({getters, commit}) {
			const project = getters.project;

			await db.set(storeName, {id: project.id, data: JSON.stringify(project)});
			//localStorage.setItem('project-' + project.id, JSON.stringify(project));
			commit('setDirty', true);
		},
		async localVersionExist({commit}, projectID) {
			let json = await db.get(storeName, projectID);
			//let json = localStorage.getItem('project-' + projectID);
			return !!json;
		},
		async loadFromLocal({commit, dispatch}, projectID) {
			await dispatch('loadPackageInfos');
			let json = await db.get(storeName, projectID);
			//let json = localStorage.getItem('project-' + projectID);
			if (json) {
				const remoteProject = await projectApi.fetchOne(projectID, false);
				const project = JSON.parse(json.data);
				project.operators = remoteProject.operators;
				project.remark = remoteProject.remark;
				commit('updateProject', project);
				commit('setDirty', true);
			}
		},
		async deleteLocalVersion({state, commit}, projectID) {
			await db.remove(storeName, projectID);
			//localStorage.removeItem('project-' + projectID);
			commit('setDirty', false);
		},
		async loadFromRemote({commit, dispatch}, {projectID}) {
			await dispatch('loadPackageInfos');
			const project = await projectApi.fetchOne(projectID);
			if (project) {
				dispatch('deleteLocalVersion', projectID);
				commit('updateProject', project);
			} else {
				throw new Error('Project does not exist')
			}
		},
		async loadFromDataUrl({commit, dispatch}, {projectID, dataUrl}) {
			const projectData = await projectApi.fetchOneFromDataUrl(dataUrl);
			if (projectData) {
				await dispatch('loadFromData', {projectID, projectData})
				dispatch('saveToLocal');
			} else {
				throw new Error('Project does not exist')
			}
		},
		async loadFromData({commit, dispatch}, {projectID, projectData}) {
			await dispatch('loadPackageInfos');
			let project = await projectApi.fetchOne(projectID, false);
			project.data = projectData;
			commit('updateProject', project);
		},
		async saveToRemote({state, dispatch, getters, commit}, {remark, data}) {
			if (data) { //如果已经合并了冲突
				commit('updateProjectUpdateTime', {time: state.base_time});
			}

			getters.project.data = getters.project.data.replace(/editScroll/g, "scroll")

			let project = Object.assign({}, getters.project);
			if (data) {
				project.data = data;
			}

			console.log("data", getters.project, project.data)

			let resp = await projectApi.saveOne(project, remark);
			if (resp.result) {
				commit('updateProjectUpdateTime', {time: resp.project.update_time, dirty: false});
				dispatch('deleteLocalVersion', state.id);
			}
			resp.localData = data || project.data;
			if (!resp.result) {
				state.base_time = resp.updateTime;
			}
			return resp;
		},
		async updateProject({commit}, projectID) {
			const project = await projectApi.getData(projectID);
			commit('updateProject', project);
		},

		/**
		 * 选中节点
		 * @param {*} context
		 * @param {*} data
		 */
		activeComponent({state, commit}, data) {
			// debugger;
			console.log("resetScrollType", data)
			resetScrollType(data.data)

			let getTopView = node => {
				//	console.log("node",node)
				if (node.parent && !node.parent.parent) {
					return node;
				} else {
					return getTopView(node.parent);
				}
			};
			let viewRoot = getTopView(data.node);

			if (state.activeView !== viewRoot) {
				commit('setActiveView', viewRoot);

				/*if (!data.fromPlayground) {
					context.state.activeViews = viewRoot.data.uuid;
				}*/
			}
			if (viewRoot.data === data.data) {
				if (!data.data.hasOwnProperty('$isViewRoot')) {
					Object.defineProperty(data.data, '$isViewRoot', {
						get() {
							return true;
						},
						enumerable: false,
					})
				}
			}

			commit('activeComponent', data.data);
		},

		/**
		 * 修改属性
		 */
		modifyProperties({commit, state, getters}, props) {
			// debugger;
			// 如果当前修改的是“来源”属性，节点又没有高度宽度，则取图片的高度宽度
			let _props = _.cloneDeep(state.activeComponent.properties);
			let hasAssetsDep = false;
			_.forIn(props, (value, key) => {
				/*if (value && value.startsWith(assetScheme) ||
					_props[key] && _props[key].startsWith(assetScheme)) {
					hasAssetsDep = true;
				}*/
				_props[key] = value;
			});

			//console.log("props",commit,state,props,state.activeComponent)
			if (nodeUUidCatch == state.activeComponent.uuid) {
				//	events.$emit('canvasKeyVupdate', {props},"update");
			}
			nodeUUidCatch = state.activeComponent.uuid
			//console.log("nodeUUidCatch",nodeUUidCatch)

			/*if (hasAssetsDep) {
				commit('updateAssetDep');
			}*/
			commit('updateAssetDep');

			if (_props.source) {
				// imageWidth imageHeight
				// 设置image类型节点的原图高宽度
				if (!_props.imageWidth || !_props.imageHeight) {
					let _url = _props.source; //_source.value;
					if (_url.indexOf(assetScheme) === 0) {
						let uuid = _url.split('//')[1];
						let asset = state.data.assets.find(a => a.uuid === uuid);
						_url = asset ? asset.url : _url;
					}
					let _img = new Image();
					_img.src = _url;
					_img.onload = function () {
						_props.imageWidth = _img.width;
						_props.imageHeight = _img.height;
						commit('modifyActiveView', {
							properties: _props
						});
					}
				}
			} else {
				delete _props.imageWidth;
				delete _props.imageHeight;
			}

			commit('modifyActiveView', {
				properties: _props
			})
		},
		/**
		 * 修改镜像的属性
		 * @param {*} param0
		 * @param {*} props
		 */
		modifyCopyProperties({commit}, props) {
			commit('modifyCopyProperties', props)
		},
		/**
		 * 修改当前选中的节点
		 */
		modifyActiveView({commit}, view) {
			commit('modifyActiveView', view)
		},
		/**
		 * 新增节点脚本
		 * @param {*} param0
		 * @param {*} script
		 */
		addNodeScript({commit, state}, script) {
			let _scripts = _.cloneDeep(state.activeComponent.scripts || []);
			_scripts.push({
				script: script,
				props: {}
			});
			commit('modifyActiveView', {
				scripts: _scripts
			})
		},
		async importView({dispatch}, {file, action, mode}) {
			let result;
			if (action === 1 || action === 2) { //普通视图
				result = await zipViewFile(file);
			} else {  //psd
				result = await toZeroing(file, {mode, singleView: action === 3});
			}
			let viewFile = new File([result], 'view.json');
			await dispatch('uploadView', {originFile: file, viewFile, action})
		},
		async uploadView({commit}, {originFile, viewFile, action}) {
			//console.log(viewFile);
			const {view, assets} = await editorApi.uploadView(viewFile);
			if (action % 2 === 1) {//视图文件
				view.name = originFile.name.substring(0, originFile.name.lastIndexOf('.'));
				commit('importView', view);
			} else {//多视图PSD
				for (let subView of view.children) {
					commit('importView', subView)
				}
			}
			commit('importAssets', assets)
		},
		exportView({state}, view) {
			let zip = new JSZip();
			zip.file('view.json', JSON.stringify(view));
			zip.generateAsync({type: "blob"}).then(function (content) {
				saveAs(content, `view-${view.name}.zrv`);
			});
		},
		async uploadFiles({commit}, files) {
			const {failedList, result} = await uploadFiles(files);
			for (let item of result) {
				const {url, __originFile} = item;
				commit('addAsset', {url, file: __originFile});
			}
			return failedList;
		},
		async replaceAsset({commit}, {uuid, file}) {
			console.log(file);
			const {failedList, result} = await uploadFiles([file]);
			commit('replaceAsset', {uuid, url: result[0].url,});
			return failedList;
		},
		async packProject({state, dispatch}, params) {
			let {debug, mix, remark} = params;
			let packedAssets;
			//if (!debug) {
			packedAssets = await packAssetsGroups(state.data.views, state.data.assets);
			//}
			console.log(packedAssets);
			const packResult = await projectApi.pack(state.id, debug, mix, packedAssets);

			console.log(packResult);

			const {tpl, tplUrl} = packResult;

			await db.set(psStoreName, {
				pid: state.id,
				time: Date.now(),
				packResult: {tpl, tplUrl},
				remark,
			});
			return packResult;
		},
		async getPackHistory({state}) {
			return (await db.getAll(psStoreName, state.id, 'pid')).reverse();
		},
		async deletePackItem({state}, id) {
			await db.remove(psStoreName, id);
		},
		savePreview({state, rootState, getters}) {
			const project = getters.project;

			const packages = state.package.packages;
			/*const data = {
				processes, scripts, customs,
				data: state.data,
			};
			localStorage.setItem('preview-project-' + project.id, JSON.stringify(data));
			localStorage.setItem('preview-ts', Date.now().toString());*/

			preprocess(project, clonePureObj(packages));
		},

		addBehaviorDirect({state}, {behaviors, alias}) {
			let behavior = addBehavior({alias, from: 'trigger'}, state.data.processes);
			behaviors.push(behavior);
		},

		deleteBehaviorDirect({state}, {behaviors, index, deleteMeta}) {
			let behavior = behaviors.splice(index, 1)[0];
			if (deleteMeta) {
				deleteProcessMeta(behavior.meta, state.data.processes);
			}
		},
		setMockServeEnabled({state, commit}, enabled) {
			localStorage.setItem('mock-enabled-' + state.id, JSON.stringify(enabled));
			commit('setMockServeEnabled', enabled);
			return enabled;
		},
		async saveRemark({state, commit}, {remark}) {
			await projectApi.updateRemark(state.id, remark);
			commit('updateRemark', remark);
		},
	},
};


function getDefaultOptions() {
	return clonePureObj(defaultOptions)
}

function setUUIDForAllChildren(node) {
	if (node.children && node.children.length > 0) {
		for (let i = 0; i < node.children.length; i++) {
			node.children[i] = copyBaseRoot(node.children[i]);
			setUUIDForAllChildren(node.children[i])
		}
	}
}

//重置编辑视图数据为实际视图数据
function resetScrollType(data) {
	if (data.type == "editScrollList") {
		data.type = "scrollList"
	}
	if (data.type == "editScrollView") {
		data.type = "scrollView"
	}
	if (data.children) {
		for (let i = 0; i < data.children.length; i++) {
			resetScrollType(data.children[i])
		}
	}
}

let copyNodeCatch = null;

function copyBaseRoot(node) {
	let _node = JSON.parse(JSON.stringify(node));

	let data;

	if (_node.children && _node.children.length > 0) {
		data = {
			name: _node.name,
			type: _node.type,
			properties: _node.properties,
			events: _node.events,
			uuid: generateUUID(),
			children: _node.children
		};
	} else {
		data = {
			name: _node.name,
			type: _node.type,
			properties: _node.properties,
			events: _node.events,
			uuid: generateUUID(),
		};
	}
	return data
}

export async function updateMock(mocks) {
	await db.clear('mock');
	for (let mock of mocks) {
		db.set('mock', mock);
	}
}
