import { defaultData } from '../script/defaultData.js';
import {
	addBtnListener,
	showTrebleFirework,
	asyncDelay,
	asyncTweenBy,
	asyncTweenTo,
	Between,
	exchangeNodePos,
	getSpriteFrimeByUrl,
	jelly,
	playAudioByUrl,
	playAudioByUrlSync,
	RandomInt,
	onHomeworkFinish,
} from "../script/util";

cc.Class({

	extends: cc.Component,

	properties: {
	},

	ctor() {
		this.createSpeed = [750, 1500, 1000, 800, 800, 640, 640, 512, 512];
		this.moveSpeed = [5, 5, 4, 4, 3.2, 3.2, 2.56, 2.56, 2.048, 2.048];
	},

	// 生命周期 onLoad
	onLoad() {
		this.initSceneData();
		this.initSize();
	},

	_imageResList: null,
	_audioResList: null,
	_animaResList: null,
	initSceneData() {
		this._imageResList = [];
		this._audioResList = [];
		this._animaResList = [];
	},

	_designSize: null,  // 设计分辨率
	_frameSize: null,  // 屏幕分辨率
	_mapScaleMin: null,  // 场景中常用缩放（取大值）
	_mapScaleMax: null,  // 场景中常用缩放（取小值）
	_cocosScale: null,  // cocos 自缩放 （较少用到）
	initSize() {
		// 注意cc.winSize只有在适配后(修改fitHeight/fitWidth后)才能获取到正确的值,因此使用cc.getFrameSize()来获取初始的屏幕大小
		let screen_size = cc.view.getFrameSize().width / cc.view.getFrameSize().height
		let design_size = cc.Canvas.instance.designResolution.width / cc.Canvas.instance.designResolution.height
		let f = screen_size >= design_size
		cc.Canvas.instance.fitHeight = f
		cc.Canvas.instance.fitWidth = !f

		const frameSize = cc.view.getFrameSize();
		this._frameSize = frameSize;

		this._designSize = cc.view.getDesignResolutionSize();

		let sx = cc.winSize.width / frameSize.width;
		let sy = cc.winSize.height / frameSize.height;
		this._cocosScale = Math.min(sx, sy);

		sx = frameSize.width / this._designSize.width;
		sy = frameSize.height / this._designSize.height;
		this._mapScaleMin = Math.min(sx, sy) * this._cocosScale;
		this._mapScaleMax = Math.max(sx, sy) * this._cocosScale;
	},


	// 生命周期 start
	start() {
		let getData = this.getData.bind(this);
		if (window && window.courseware) {
			getData = window.courseware.getData;
		}

		getData((data) => {
			console.log('data:', data);
			this.data = data || this.getDefaultData();
			this.data = JSON.parse(JSON.stringify(this.data))
			this.preloadItem()
		});
	},

	getData(cb) {
		cb(this.getDefaultData());
	},

	getDefaultData() {
		return defaultData;
	},

	preloadItem() {
		this.addPreloadImage();
		this.addPreloadAudio();
		this.addPreloadAnima();
		this.preload();
	},

	addPreloadImage() {
		// this._imageResList.push({ url: this.data.pic_url });
	},

	addPreloadAudio() {
		// this._audioResList.push({ url: this.data.audio_url });
	},

	addPreloadAnima() {

	},

	preload() {
		const preloadArr = this._imageResList.concat(this._audioResList).concat(this._animaResList);
		cc.assetManager.loadAny(preloadArr, null, null, (err, data) => {
			this.loadEnd();
			if (window && window["air"]) {
				window["air"].hideAirClassLoading();
			}
			cc.debug.setDisplayStats(false);
		});
	},


	loadEnd() {
		this.initData();
		this.initAudio();
		this.initView();
		this.initListeners();
	},

	_cantouch: null,
	initData() {
		// 所有全局变量 默认都是null 
		this._cantouch = true;
	},

	initAudio() {

	},

	initView() {
		cc.find('Canvas').on('size-changed', this.onSizeChanged.bind(this));
		this.initBg();
		this.createStars();
	},

	onSizeChanged() {
		cc.director.loadScene(cc.director.getScene().name);
	},

	initListeners() {
		const BtnStart = cc.find('Canvas/bg/BtnStart');
		addBtnListener(BtnStart, async () => {
			await asyncTweenTo(BtnStart, 0.1, { opacity: 0 });
			BtnStart.active = false;
			this.gameStart();
		}, this.playAudio.bind(this, 'btn'));
		const BtnRestart = cc.find('Canvas/bg/BtnRestart');
		addBtnListener(BtnRestart, async () => {
			await asyncTweenTo(BtnRestart, 0.1, { opacity: 0 });
			BtnRestart.active = false;
			this.gameStart();
		}, this.playAudio.bind(this, 'btn'));
		const BtnSpeaker = cc.find('Canvas/bg/BtnSpeaker');
		addBtnListener(BtnSpeaker, async () => {
			await this.playQuestionAudio();
		});

		const bg = cc.find('Canvas/bg');
		bg.on('touchstart', (event) => {
			this.shootTarget(bg, event.getLocation(), false);
		});
	},

	initBg() {
		const bgNode = cc.find('Canvas/bg');
		bgNode.scale = this._mapScaleMax;

		const table = cc.find('Canvas/bg/Table');
		table.zIndex = 1;
		const gunBase = cc.find('Canvas/bg/GunBase');
		gunBase.zIndex = 1;
		const speaker = cc.find('Canvas/bg/BtnSpeaker');
		speaker.zIndex = 1;
	},

	createStars() {
		let length = 1;
		const starLayout = cc.find('Canvas/bg/StarLayout');
		starLayout.removeAllChildren();
		starLayout.zIndex = 2;
		const paddingY = starLayout.getComponent(cc.Layout).spacingY;

		if (this.data.questionList.length == 1) {
			starLayout.active = false;
		}

		for (let i = 0; i < this.data.questionList.length; i++) {
			const starBase = cc.instantiate(cc.find('StarBase'));
			starBase.name = `starBase_${i}`;
			starBase.scale = Between(0.5, (starLayout.height / length - paddingY) / starBase.height, 1);
			starBase.parent = starLayout;
		}
	},

	async showStar() {
		const starBase = cc.find(`Canvas/bg/StarLayout/starBase_${this._status.currentQuestionIdx}`);
		if (!starBase) {
			return;
		}
		const star = starBase.getChildByName('Star');
		star.active = true;
		const starBig = star.getChildByName('StarBig');
		starBig.scale = 1;
		star.active = true;
		star.scaleX = 0.7 / starBase.scale;
		star.scaleY = 1 / starBase.scale;
		star.angle = 90;
		const canvas = cc.find('Canvas');
		const startPos = star.parent.convertToNodeSpaceAR(canvas.convertToWorldSpaceAR(cc.v2(0, -canvas.height / 2)));
		const middlePos = star.parent.convertToNodeSpaceAR(canvas.convertToWorldSpaceAR(cc.v2(0, -canvas.height / 4)));
		star.x = startPos.x;
		star.y = startPos.y - starBig.height;

		this.playAudio('star');

		cc.tween(star)
			.to(0.3, { y: middlePos.y + 80 }, { easing: 'quadOut' })
			.to(0.1, { y: middlePos.y + 40, scaleX: 1.2 / starBase.scale, scaleY: 0.8 / starBase.scale }, { easing: 'quadOut' })
			.to(0.1, { y: middlePos.y, scaleX: 1 / starBase.scale, scaleY: 1 / starBase.scale }, { easing: 'quadOut' })
			.delay(0.1)
			.to(0.8, { angle: -720, scale: 1 })
			.start();

		cc.tween(star)
			.delay(0.6)
			.to(0.8, { x: 0 }, { easing: 'quadIn' })
			.start();
		cc.tween(star)
			.delay(0.6)
			.to(0.8, { y: 0 }, { easing: 'quadOut' })
			.start();

		await asyncDelay(0.6);
		await asyncTweenTo(starBig, 0.8, { scale: 0 }, { easing: 'quadOut' });
		await this.playAudioSync('question');
	},

	isEndGame() {
		return this._status.currentQuestionIdx >= this.data.questionList.length;
	},

	onGameEnd() {
		showTrebleFirework(cc.find('Canvas/bg'), cc.find('RabbonBase').children);
		this.playAudio('end');
		onHomeworkFinish();
		this.hideGuns();
		const BtnRestart = cc.find('Canvas/bg/BtnRestart');
		BtnRestart.active = true;
		BtnRestart.opacity = 255;
	},

	async gameStart() {
		this._status = {
			currentQuestionIdx: 0,
			currentRightNumber: 0
		};
		this.createStars();
		await this.showGuns();

		await this.playQuestionAudio();
		this.startShowBalls();
	},

	showGuns() {
		return new Promise((resolve, reject) => {
			try {
				const bg = cc.find('Canvas/bg');
				const gunBase = cc.find('Canvas/bg/GunBase');
				asyncTweenTo(gunBase, 0.5, { y: -bg.height / 2 });
				this.playAudio('move', () => {
					resolve();
				});
			} catch (e) {
				reject();
			}
		});
	},

	hideGuns() {
		const bg = cc.find('Canvas/bg');
		const gunBase = cc.find('Canvas/bg/GunBase');
		this.playAudio('move');
		asyncTweenTo(gunBase, 0.5, { y: -bg.height / 2 - gunBase.height });
	},

	showBallsinterval: null,
	startShowBalls() {
		const currentQuestion = this.data.questionList[this._status.currentQuestionIdx];
		const answerList = currentQuestion.answerList;
		const time = this.createSpeed[currentQuestion.speedLevel];

		this.ballList = [];

		const answer = answerList[RandomInt(answerList.length)];
		const ball = this.createBall(answer);
		this.ballList.push(ball);
		this.showBallsinterval = setInterval(() => {
			const answer = answerList[RandomInt(answerList.length)];
			const ball = this.createBall(answer);
			this.ballList.push(ball);
		}, time);
	},

	stopShowBalls() {
		if (this.showBallsinterval) {
			clearInterval(this.showBallsinterval);
		}
		if (this.ballList) {
			this.ballList.forEach(ball => {
				ball.stopAllActions();
				cc.tween(ball)
					.to(0.5, { opacity: 0 })
					.removeSelf()
					.start();
			});
			this.ballList = [];
		}
	},


	createBall(answer) {
		let ball = null;
		if (answer.answerType == 'img') {
			ball = this.createImgBall(answer);
		} else {
			ball = this.createTextBall(answer);
		}

		const bg = cc.find('Canvas/bg');
		let ballPosXBaseList = [-bg.width / 4, 0, bg.width / 4];
		if (this.lastBallPosXBase !== undefined) {
			ballPosXBaseList = ballPosXBaseList.filter(posX => posX != this.lastBallPosXBase);
		}

		const ballPosXBase = ballPosXBaseList[RandomInt(ballPosXBaseList.length)];
		ball.x = ballPosXBase + RandomInt(-50, 50);
		ball.y = -bg.height / 2;
		ball.parent = bg;

		this.lastBallPosXBase = ballPosXBase;

		if (answer.rightAnswer) {
			ball.audio = answer.answerAudio;
		}

		cc.tween(ball.getChildByName('bg'))
			.to(0.2, { scaleX: 0.98, scaleY: 1.05 })
			.to(0.2, { scaleX: 1.02, scaleY: 0.94 })
			.union()
			.repeatForever()
			.start();

		this.playAudio('appare', null, 0.1);

		ball.on('touchstart', async (event) => {
			if (ball.canNotTouch) {
				return;
			}
			if (answer.rightAnswer) {
				ball.canNotTouch = true;
			}
			const location = event.getLocation();
			await this.shootTarget(ball, location, true);
			if (!answer.rightAnswer) {
				this.targetLaugh(ball);
				return;
			}
			this.targetDistroy(ball);
			this._status.currentRightNumber++;
			const currentQuestion = this.data.questionList[this._status.currentQuestionIdx];
			this.updateRightNumber();
			if (this._status.currentRightNumber >= currentQuestion.rigthNumber) {
				this.stopShowBalls();
				await asyncDelay(0.5);
				await this.showStar();
				this._status.currentRightNumber = 0;
				this._status.currentQuestionIdx++;
				if (this.isEndGame()) {
					this.onGameEnd();
				} else {
					await asyncDelay(1.5);
					await this.playQuestionAudio();
					this.startShowBalls();
				}
			}
		});

		const currentQuestion = this.data.questionList[this._status.currentQuestionIdx];
		const time = this.moveSpeed[currentQuestion.speedLevel];
		const targetY1 = bg.height / 2 - ball.height / 2 - 50;
		const targetY2 = bg.height;
		const time1 = time * (ball.y - targetY1) / (ball.y - targetY2);
		const time2 = time - time1;
		cc.tween(ball)
			.to(time1, { y: bg.height / 2 - ball.height / 2 - 50 }, { easing: 'quadOut' })
			.delay(0.5)
			.to(time2, { y: bg.height }, { easing: 'quadIn' })
			.removeSelf()
			.start();

		ball.moveSpeed = bg.height / time;
		return ball;
	},

	onBallClicked(answer) {

	},

	createImgBall(answer) {
		const ball = cc.instantiate(cc.find('BallImg'));
		const img = cc.find('Mask/AnsterImg', ball);
		const mask = cc.find('Mask', ball);
		getSpriteFrimeByUrl(answer.answerImg, (spriteFrame) => {
			img.getComponent(cc.Sprite).spriteFrame = spriteFrame;
			img.scale = Math.min(1, mask.width / img.width, mask.height / img.height);
		});
		return ball;
	},

	createTextBall(answer) {
		const ball = cc.instantiate(cc.find('BallTxt'));
		const mask = cc.find('Mask', ball);
		const text = cc.find('Mask/AnswerText', ball);
		text.getComponent(cc.RichText).string = `<color=#37397b>${answer.answerTxt}</color>`;

		cc.tween(text)
			.delay(0)
			.call(() => {
				text.scale = Math.min(mask.width / text.width, 1);
			})
			.start();

		return ball;
	},

	updateRightNumber() {
		this._status.currentRightNumber;
		const totalRightNumber = this.data.questionList[this._status.currentQuestionIdx].rigthNumber;
		const starBase = cc.find(`Canvas/bg/StarLayout/starBase_${this._status.currentQuestionIdx}`);
		const mask = starBase.getChildByName('Mask');
		const bg = starBase.getChildByName('bg');

		cc.tween(mask)
			.to(0.3, { height: bg.height * (this._status.currentRightNumber / totalRightNumber) })
			.start();
	},

	async playQuestionAudio() {
		if (!this._status) {
			return;
		}
		const currentQuestion = this.data.questionList[this._status.currentQuestionIdx];
		if (!currentQuestion) {
			return;
		}
		this.speakerBlink();
		await playAudioByUrlSync(currentQuestion.questionAudio);
		this.speakerStopBlink();
	},

	speakerList: null,
	speakerBlink() {
		const btnSpeaker = cc.find(`Canvas/bg/BtnSpeaker`);
		btnSpeaker.getComponent(cc.Animation).play();
	},

	speakerStopBlink() {
		const btnSpeaker = cc.find(`Canvas/bg/BtnSpeaker`);
		const btnSpeaker3 = cc.find(`Canvas/bg/BtnSpeaker/speaker_3`);
		btnSpeaker.getComponent(cc.Animation).stop();
		btnSpeaker.getComponent(cc.Sprite).spriteFrame = btnSpeaker3.getComponent(cc.Sprite).spriteFrame;
	},

	async shootTarget(node, location, shootBullet) {
		const GunPos = cc.find('Canvas/bg/GunBase/GunPos');
		const Gun = cc.find('Canvas/bg/GunBase/Gun');
		const Water = cc.find('Canvas/bg/GunBase/Gun/Water');
		const Muzzle = cc.find('Canvas/bg/GunBase/Gun/Muzzle');
		const bg = cc.find('Canvas/bg')
		let offsetY = 0;
		if (node.moveSpeed) {
			offsetY = node.moveSpeed * 0.4;
		}
		const shootSide = GunPos.convertToNodeSpaceAR(cc.v2(location.x, location.y + offsetY));

		const bullet = cc.instantiate(cc.find('Bullet'));
		bullet.parent = bg;
		bullet.scaleY = 0;
		if (!shootBullet) {
			bullet.opacity = 0;
		}

		const angle = cc.v2(0, 1).signAngle(shootSide) * 180 / Math.PI;
		bullet.angle = angle;

		asyncTweenTo(Water, 0.1, { angle: -angle });
		await asyncTweenTo(Gun, 0.1, { angle: angle, scaleY: 0.95 });
		let startPos = exchangeNodePos(bg, Muzzle);
		bullet.x = startPos.x;
		bullet.y = startPos.y;

		cc.tween(Gun)
			.to(0.1, { scaleX: 0.95, scaleY: 1.05 })
			.to(0.1, { scaleX: 1, scaleY: 1 })
			.start();

		this.playAudio('light');

		let targetPos = bg.convertToNodeSpaceAR(cc.v2(location.x, location.y + offsetY));
		let flySide = cc.v2(targetPos.x - startPos.x, targetPos.y - startPos.y);
		await asyncTweenTo(bullet, 0.1, {
			scaleY: flySide.mag() / bullet.height,
			scaleX: Between(0.5, 1, bullet.height / flySide.mag())
		});

		bullet.setAnchorPoint(0.5, 1);
		bullet.x = targetPos.x;
		bullet.y = targetPos.y;

		asyncTweenTo(bullet, 0.2, { opacity: 0, scaleY: 0 });
	},

	async targetDistroy(node) {
		node.stopAllActions();
		const bg = node.getChildByName('bg');
		bg.active = false;
		const DistroyAnime = node.getChildByName('DistroyAnime');
		DistroyAnime.active = true;
		const Mask = node.getChildByName('Mask');
		cc.tween(Mask)
			.to(0.5, { opacity: 0 })
			.start();

		await this.playAudioSync('right');
		await playAudioByUrlSync(node.audio);
		node.removeFromParent();
	},

	async targetLaugh(node) {
		this.playAudio('wrong');
		const x = node.x;
		let offsetX = RandomInt(20, 50) * 2 * (RandomInt(2) - 0.5);
		let offsetY = RandomInt(20, 50) * 2 * (RandomInt(2) - 0.5);
		await asyncTweenBy(node, 0.05, { x: offsetX, y: offsetY });
		offsetX = RandomInt(20, 50) * 2 * (RandomInt(2) - 0.5);
		offsetY = RandomInt(20, 50) * 2 * (RandomInt(2) - 0.5);
		await asyncTweenBy(node, 0.05, { x: offsetX, y: offsetY });
		await asyncTweenTo(node, 0.05, { x: x });
	},

	playAudio(audioName, cb, value = 0.8) {
		const audioNode = cc.find(`AudioBase/${audioName}`);
		const audioClip = audioNode.getComponent(cc.AudioSource).clip;
		const id = cc.audioEngine.play(audioClip, false, value);
		cc.audioEngine.setFinishCallback(id, () => {
			if (cb) {
				cb();
			}
		});
	},
	async playAudioSync(audioName, value) {
		return new Promise((resolve, reject) => {
			try {
				this.playAudio(audioName, () => {
					resolve();
				}, value);
			} catch (e) {
				reject();
			}
		});
	}
});
