import { asyncDelay, randomSortByArr } from "./util";

export abstract class middleLayerBase extends cc.Component {

	abstract reWriteAir(): void;

	isShowWaiting = false;
	isDestroy = false;
	hideWaitingLetters(){
		this.isShowWaiting = false;

		const layout = cc.find('middleLayer/layout');
		layout.active = false;

		const laodingLayer = cc.find('middleLayer/loadingLayer');
		laodingLayer.active = false;

		const laodingLayerBG = cc.find('middleLayer/bg');
		laodingLayerBG.active = false;
	}
	showWaitingLetters(){
		if (this.isShowWaiting) {
		return;
		}
		this.isShowWaiting = true;

		const layout = cc.find('middleLayer/layout');
		layout.removeAllChildren();

		//const canvas = cc.find("Canvas");
		//const bg = layout.addComponent(cc.Graphics);		
		//bg.fillRect(-canvas.width / 2, -canvas.height / 2, canvas.width, canvas.height);


		const laodingLayer = cc.find('middleLayer/loadingLayer');
		laodingLayer.active = true;

		const laodingLayerBG = cc.find('middleLayer/bg');
		laodingLayerBG.active = true;
		const screenSize = cc.view.getVisibleSize();
		// 计算缩放比例，以确保 Sprite 铺满屏幕
		const scaleX = screenSize.width / laodingLayerBG.width;
		const scaleY = screenSize.height / laodingLayerBG.height;
		// 设置节点的缩放
		laodingLayerBG.scaleX = scaleX;
		laodingLayerBG.scaleY = scaleY;


		const script = cc.find('middleLayer/loadingLayer/progress').getComponent('progressScript');
		script.setProgress(0);

		const id = setInterval(() => {
		script.setProgress(changeObj.value);
		}, 1);

		const changeObj = { value: 0 };
		cc.tween(changeObj)
		.to(5, { value: 0.9 })
		.call(() => {
			clearInterval(id);
		})
		.start();
	}

	oldSceneName = null;
	IS_BUNDLE_LOADING = false;

	callNetworkApiPost(uri, data, callBack) {
		const xhr = new XMLHttpRequest();
		const url = `${this.API_BASE}${uri}`;
		xhr.open("POST", url, true);
		xhr.setRequestHeader('content-type', 'application/json');
		xhr.onreadystatechange = () => {
			if (xhr.readyState == 4) {
				callBack(JSON.parse(xhr.responseText));
			}
		}
		xhr.send(JSON.stringify(data));
	}

	callNetworkApiGet(uri, data, callBack) {
		let queryStr = '?';
		const params = [];
		for (const key in data) {
			if (Object.hasOwnProperty.call(data, key)) {
				params.push(`${key}=${data[key]}`);
			}
		}
		queryStr += params.join("&");
		const xhr = new XMLHttpRequest();
		xhr.onreadystatechange = () => {
			if (xhr.readyState == 4 && (xhr.status >= 200 && xhr.status < 400)) {
				callBack(xhr.responseText);
			}
		};
		const url = `${this.API_BASE}${uri}${queryStr}`;
		console.log('url = ' + url);
		xhr.open('GET', url, true);
		xhr.send();
	}

	getConfigInfo(url, callback) {
		const xhr = new XMLHttpRequest();
		xhr.onreadystatechange = () => {
			if (xhr.readyState == 4 && (xhr.status >= 200 && xhr.status < 400)) {
				callback(JSON.parse(xhr.responseText));
			}
		};
		console.log('url = ' + `${url}/config.json`);
		xhr.open('GET', `${url}/config.json`, true);
		xhr.send();
	}

	DOMAIN = "http://staging-teach.cdn.ireadabc.com/";
	API_BASE = "http://staging-openapi.iteachabc.com/";
	
	asyncCallNetworkApiGet(apiName, data): Promise<any> {
		return new Promise((resolve, reject) => {
			this.callNetworkApiGet(apiName, data, (res => {
				resolve(res);
			}));
		});
	}
	asyncCallNetworkApiPost(uri, data): Promise<any> {
		return new Promise((resolve, reject) => {
			this.callNetworkApiPost(uri, data, (res) => {
				resolve(res);
			});
		});
	}

	loadOnlineBundle(bundleName, callback = null) {
		if (this.IS_BUNDLE_LOADING) {
			return;
		}
		this.IS_BUNDLE_LOADING = true;
		console.log(' in loadOnlineBundle')
		this.callNetworkApiGet(`api/template/v2/${bundleName}`, {}, (datastr) => {
			const data = JSON.parse(datastr).data;
			let sceneName, version, bondleUrl = "";

			const templateBaseUrl = `${this.DOMAIN}h5template/${data.name}/v${data.last_version}`;
			this.getConfigInfo(templateBaseUrl, (conf) => {

				if (cc.sys.os == cc.sys.OS_IOS) {
					sceneName = conf.ios.sceneName;
					version = conf.ios.version;
					bondleUrl = `${templateBaseUrl}/ios/${conf.ios.sceneName}`;
				} else if (cc.sys.os == cc.sys.OS_ANDROID) {
					sceneName = conf.android.sceneName;
					version = conf.android.version;
					bondleUrl = `${templateBaseUrl}/android/${conf.ios.sceneName}`;
				} else {
					sceneName = conf.android.sceneName;
					version = "";
					bondleUrl = `${templateBaseUrl}/web_desktop`;
				}
				this.loadBundle(sceneName, version, bondleUrl, callback);
			});
		});
	}
	currentBundleInfo = null;

	reloadBundle() {
		if (this.IS_BUNDLE_LOADING) {
			return;
		}
		this.IS_BUNDLE_LOADING = true;
		const { sceneName, version, bondleUrl } = this.currentBundleInfo;
		this.loadBundle(sceneName, version, bondleUrl);
	}

	async loadBundle(sceneName, version, bondleUrl, callback = null) {

		if (this.oldSceneName) {
			await this.checkRotateScreen(this.oldSceneName, sceneName);
		}

		this.assetList = [];
		this.textureList = [];
		this.assetObj = {};
		this.atlasList = [];
		this.nodeList = [];
		this.getDragonDisplayAssetList(cc.find('Canvas'));

		this.currentBundleInfo = { sceneName, version, bondleUrl };
		this.showWaitingLetters();
		cc.audioEngine.stopAll();

		this.setNodeListVisible();

		// 手机端强制垃圾回收
		if (cc.sys.os == cc.sys.OS_IOS || cc.sys.os == cc.sys.OS_ANDROID) {
			cc.sys.garbageCollect();
		}

		cc.assetManager.loadBundle(bondleUrl, { version: version }, async (err, bundle) => {
			if (this.isDestroy) {
				// 已退出
				return;
			}
			bundle.loadScene(sceneName, null, null, (err, scene) => {
				if (this.isDestroy) {
					// 已退出
					return;
				}
				this.courseOpenTimeStamp = Date.now();

				cc.director.runScene(scene, null, () => {
					if (this.isDestroy) {
						// 已退出
						return;
					}
					
					console.log('sceneName = ' + sceneName);
					const canvas = cc.find('Canvas');
					const middleLayer = cc.find('middleLayer');
					this.hideWaitingLetters();
					canvas.getComponent(cc.Widget).updateAlignment();
					middleLayer.scale = canvas.width / middleLayer.width;

					// 挂载清洁骨骼机制节点
					const destroyer = cc.instantiate(cc.find('middleLayer/Destroyer'));
					destroyer.parent = cc.find('Canvas');
					destroyer.active = true;


					// 手机端强制垃圾回收
					if (cc.sys.os == cc.sys.OS_IOS || cc.sys.os == cc.sys.OS_ANDROID) {
						cc.sys.garbageCollect();
					}		

					callback && callback();
					this.IS_BUNDLE_LOADING = false;
					this.oldSceneName = sceneName;
				});
			});
		});
	}

	setNodeListVisible() {
		const setParentVisible = (n) => {
			n.active = true;
			if (n.parent) {
				setParentVisible(n.parent);
			}
		}

		this.nodeList.forEach(node => {
			setParentVisible(node);
		});
	}

	getUUID() {
		return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
			var r = Math.random() * 16 | 0,
				v = c == 'x' ? r : (r & 0x3 | 0x8);
			return v.toString(16);
		});
	}

	checkRotateScreen(oldSceneName: string, newSceneName: string) {
		const sceneNameList = ["cc_mz_link_write_03"];
		if (sceneNameList.includes(oldSceneName) || sceneNameList.includes(newSceneName)) {
			return new Promise((resolve, reject) => {
				if (sceneNameList.includes(newSceneName)) {
					// 如果已经是竖屏了
					if (cc.view.getCanvasSize().width < cc.view.getCanvasSize().height) {
						resolve(null);
						return;
					}
					// 旋转到竖屏
					(<any>window).courseware.onConfigurationPortrait({}, async () => {
						while (cc.view.getCanvasSize().width > cc.view.getCanvasSize().height) {
							await asyncDelay(0.1);
						}
						resolve(null);
					});
				} else {
					// 如果已经是横屏了
					if (cc.view.getCanvasSize().width > cc.view.getCanvasSize().height) {
						resolve(null);
						return;
					}
					// 旋转到横屏
					(<any>window).courseware.onConfigurationLandscape({}, async () => {
						while (cc.view.getCanvasSize().width < cc.view.getCanvasSize().height) {
							await asyncDelay(0.1);
						}
						resolve(null);
					});
				}
			});
		}
	}

	courses = null;
	courseIndex = 0;
	courseItem = null;
	courseOpenTimeStamp = null;
	loadOnlineCourseWare(courseId, linkFlag = false, coursewareId = null) {
		if (this.IS_BUNDLE_LOADING) {
			return;
		}
		this.IS_BUNDLE_LOADING = true;

		this.showWaitingLetters();

		let api = `api/courseware/v2/${courseId}/list`;
		if (linkFlag === true) {
			api = `api/courseware/v2/${courseId}/eq/level/list`;
		}

		this.callNetworkApiGet(api, {}, (datastr) => {
			if (this.isDestroy) {
				// 已退出
				return;
			}
			const data = JSON.parse(datastr);
			if (data.rows && data.rows.length > 0) {
				this.courses = data.rows;
				if (coursewareId) {
					this.courseIndex = data.rows.findIndex(item => item.id == coursewareId);
				} else {
					this.courseIndex = data.index || 0;
				}
				this.courseItem = data.rows[this.courseIndex];
			} else {
				this.hideWaitingLetters();
				this.showTips(`内容还未制作`);
				this.IS_BUNDLE_LOADING = false;
				return;
			}
			this.loadPageBundle(() => {
			});
		});
	}

	loadPageBundle(callback = null) {
		console.log(" in loadPageBundle");
		let sceneName, version, bondleUrl = "";
		const templateBaseUrl = `${this.DOMAIN}h5template/${this.courseItem.template_name}/v${this.courseItem.last_version}`;
		this.getConfigInfo(templateBaseUrl, (conf) => {
			if (this.isDestroy) {
				// 已退出
				return;
			}
			if (cc.sys.os == cc.sys.OS_IOS) {
				sceneName = conf.ios.sceneName;
				version = conf.ios.version;
				bondleUrl = `${templateBaseUrl}/ios/${conf.ios.sceneName}`;
			} else if (cc.sys.os == cc.sys.OS_ANDROID) {
				sceneName = conf.android.sceneName;
				version = conf.android.version;
				bondleUrl = `${templateBaseUrl}/android/${conf.ios.sceneName}`;
			} else {
				sceneName = conf.android.sceneName;
				version = "";
				bondleUrl = `${templateBaseUrl}/web_desktop`;
			}
			this.loadBundle(sceneName, version, bondleUrl, callback);
		});
	}

	goPrePage() {
		this.goTarIndexPage(this.courseIndex - 1);
	}
	goNextPage() {
		this.goTarIndexPage(this.courseIndex + 1);
	}
	goTarIndexPage(index) {
		if (this.IS_BUNDLE_LOADING) {
			return;
		}
		this.IS_BUNDLE_LOADING = true;
		if (!this.courses || index == this.courseIndex || index < 0 || index > this.courses.length - 1) {
			this.IS_BUNDLE_LOADING = false;
			return;
		}

		this.showWaitingLetters();
		
		(<any>window).courseware.freeAllOcMethod();

		this.courseIndex = index;
		this.courseItem = this.courses[this.courseIndex];

		this.loadPageBundle();
	}

	showTips(str: string) {
		const tipsNode = new cc.Node();
		tipsNode.parent = cc.find('Canvas');
		tipsNode.zIndex = 100;

		const bg = cc.instantiate(cc.find('middleLayer/bg'));
		bg.parent = tipsNode;
		bg.active = true;
		bg.color = cc.color(100, 100, 100);

		const labelNode = new cc.Node();
		labelNode.parent = tipsNode;
		const label = labelNode.addComponent(cc.Label);
		label.string = str;

		bg.width = 200;
		bg.height = labelNode.height + 20;

		cc.tween(tipsNode)
			.set({ opacity: 255 })
			.delay(1)
			.to(1, { opacity: 0 })
			.removeSelf()
			.start();
	}

	log(str) {
		console.log(str);
	}

	async clearDragonDisplayAssetList() {
		if (this.atlasList.length == 0) {
			return;
		}

		this.setNodeListVisible();

		for (let i=0; i<this.atlasList.length; i++) {
			const atlas = this.atlasList[i];
			const asset = this.assetList[i];
			const texture = this.textureList[i];
			const node = this.nodeList[i];


			atlas.decRef();
			cc.assetManager.releaseAsset(atlas);
			atlas.destroy();

			asset.decRef();
			cc.assetManager.releaseAsset(asset);
			asset.destroy();

			texture.decRef();

		}

		
	}

	assetObj = null;
	nodeList = null;
	atlasList = null;
	assetList = null;
	textureList = null;
	getDragonDisplayAssetList(node) {

		const dragonDisplay = node.getComponent(dragonBones.ArmatureDisplay);
		if (dragonDisplay) {
			const atlas = dragonDisplay.dragonAtlasAsset;
			const asset = dragonDisplay.dragonAsset;

			if (atlas && atlas.texture) {
				if (atlas.texture.nativeUrl.includes('h5template')) {
					node.children.forEach(child => {
						this.getDragonDisplayAssetList(child);
					});
					return;
				}

				this.nodeList.push(node);
				this.atlasList.push(atlas);
				this.assetList.push(asset);
				this.textureList.push(atlas.texture);
			}
		}

		node.children.forEach(child => {
			this.getDragonDisplayAssetList(child);
		});
	}

	toCleanParent() {
		const canvas = cc.find("Canvas");

		this.nodeList.forEach(node => {
			node.parent = canvas;
		});
	}

	onDestroy() {
		this.isDestroy = true;
	}

}