import { onHomeworkFinish, RandomInt, playAudioByUrl, loadDragonBones, getSpriteFrimeByUrl } from "../script/util";
import { defaultData } from "../script/defaultData";
import { assign, createMachine, interpret, actions, forwardTo, matchesState  } from "../script/xstate";
const { pure , send, raise, sendParent  } = actions;


cc.Class({

	extends: cc.Component,

	properties: {
		/*ant: {
			default: null,
			type: cc.Node,
		},
		apple: {
			default: null,
			type: cc.Node,
		},
		bird: {
			default: null,
			type: cc.Node,
		},
		car: {
			default: null,
			type: cc.Node,
		},
		cat: {
			default: null,
			type: cc.Node,
		},
		cow: {
			default: null,
			type: cc.Node,
		},
		duck: {
			default: null,
			type: cc.Node,
		},
		egg: {
			default: null,
			type: cc.Node,
		},
		farmer: {
			default: null,
			type: cc.Node,
		},
		fish: {
			default: null,
			type: cc.Node,
		},
		girl: {
			default: null,
			type: cc.Node,
		},
		hen: {
			default: null,
			type: cc.Node,
		},
		house: {
			default: null,
			type: cc.Node,
		},*/
		rightAudio: {
			default: null,
			type: cc.AudioClip,
		},
		wrongAudio: {
			default: null,
			type: cc.AudioClip,
		},

	},

	playAni(idx, name, options) {
		const times = (options && options.times) || 1;
		const cb = (options && options.callback) || null;
		// const cat = cc.find(`Canvas/frame-border/ground/${node}`);
		const node = this._figurePointRectArray[idx].node
		var dragonDisplay = node.getComponent(dragonBones.ArmatureDisplay);

		const state = dragonDisplay.playAnimation(name, times);
		// animationDisplay.addEventListener(dragonBones.EventObject.COMPLETE, completeCallback);
		return state;
	},
	// 生命周期 onLoad
	onLoad() {
		this.initSceneData();
		this.initSize();
		window.ccc = this;
	},

	_imageResList: null,
	_audioResList: null,
	_animaResList: null,

	_lastFingerPosition: null,

	_hintsNodeList : null,
	_figurePointRectArray: null,

	initSceneData() {
		this._imageResList = [];
		this._audioResList = [];
		this._animaResList = [];

		this._hintsNodeList = [];
		this._lastFingerPosition= {
			pos: null,
			dirty: false
		};
		this._figurePointRectArray = [];
	},

	_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;
	},
	createStateMachine(){
		const check =  [
							{ target: '#game.end', cond: (ctx, evt) => {
								console.log('[answer NEXT] check if end', ctx.questionIndex >= ctx.questionsCount - 1);
								return ctx.questionIndex >= ctx.questionsCount -1

							} },
        					{ target: 'hint' } // reenter 'hint' state
						]
		const QuestionState = {
			id: 'question',
			initial: 'hint',
			states: {
				hint: {
					invoke: {
						src: (ctx, event) => {
							console.log(`[hint] play question ${ctx.questionIndex}: ${ctx.questionPlayTimes } audio`);
							ctx.questionPlayTimes += 1;
							return new Promise((resolve,reject) => {
								
								playAudioByUrl(ctx.questions[ctx.questionIndex].audio_url, () => {
									console.log('hint finish');
									resolve()
								})
							})
						},
						onDone: 'answer',
						onError: 'answer'
					}
				},
				answer: {
					after: {
						5000: [
							// { 
							// 	target: '#QuestionsArray.next', 
							// 	actions: raise('CHECK'),
							// 	cond: (ctx, evt) => {
							// 		console.log('[timeout check] #QuestionsArray.next', ctx.questionPlayTimes , ctx.maxQuestionTryTimes, (ctx.questionPlayTimes >= ctx.maxQuestionTryTimes));
							// 		return ctx.questionPlayTimes >= ctx.maxQuestionTryTimes;
							// 	}, 
							// },
        					{ 
								target: 'wrong',
								// cond: (ctx, evt) => {
								// 	console.log('[timeout check] wrong', ctx.questionPlayTimes , ctx.maxQuestionTryTimes, (ctx.questionPlayTimes < ctx.maxQuestionTryTimes));
								// 	return ctx.questionPlayTimes < ctx.maxQuestionTryTimes;
								// }, 
							} // reenter 'hint' state
						]
						
					},
					
					invoke: {
						
						src: (context, event) => (callback, onReceive) => {
							
							console.log('[answer] thinking and playing');
							// This will send the 'INC' event to the parent every second
							const id = setInterval(() => {
								
								const region = context.questions[context.questionIndex];
								const result = this.checkInRegion(region.rect);
								console.log('checkInRegion', JSON.stringify(this._lastFingerPosition), JSON.stringify(region.rect), result);
								if (result) {
									callback('RIGHT')
									// playAudioByUrl(this.data.begin_audio, () => {
									// 	console.log('game begin audio finish');
									// })
								} else if (this._lastFingerPosition.dirty) {
									callback('WRONG')
								}
							}, 1000);
					
							// Perform cleanup
							return () => clearInterval(id);
						},
						
					},
					on: {
						RIGHT: {
							target: 'right',
						},
						WRONG: {
							target: 'wrong',
						}
					}
				},
				
				right: {
					invoke: {
						src: (context, event) => {
							this._lastFingerPosition.pos = null;
							this._lastFingerPosition.dirty = false;
							return new Promise((resolve, reject) => {
								console.log('answer right');
								// this.playAni(context.questionIndex, 'normal')
								const an = context.questions[context.questionIndex].node;
								an.active = true;
								const dragonDisplay = an.getComponent(dragonBones.ArmatureDisplay);
								dragonDisplay.playAnimation('normal', 0);
								playAudioByUrl(this.rightAudio, () => {
									resolve()
								})
							});
						},
						onDone: {
							target: '#QuestionsArray.next',
							actions: raise('CHECK')
						},
						onError: {
							target: '#QuestionsArray.next',
							actions: raise('CHECK')
						}
					}
				},
				wrong:{
					invoke: {
						src: (context, event) => {
							console.log(1111)
							this._lastFingerPosition.pos = null;
							this._lastFingerPosition.dirty = false;
							return new Promise((resolve, reject) => {
								console.log('answer wrong', context.questionPlayTimes , context.maxQuestionTryTimes);
								playAudioByUrl(this.wrongAudio, () => {
									if (context.questionPlayTimes >= context.maxQuestionTryTimes) {
										const an = context.questions[context.questionIndex].node;
										an.active = true;
										const dragonDisplay = an.getComponent(dragonBones.ArmatureDisplay);
										dragonDisplay.playAnimation('normal', 0);
										console.log('show animation', an.active);
										reject()
									} else {
										resolve()
									}
									
								})
							});
						},
						onDone: {
							target: 'hint',
							// actions: raise('CHECK')
						},
						onError: {
							target: '#QuestionsArray.next',
							actions: raise('CHECK')
						}
					}
				},
				
				

			}
		}
		const QuestionsArrayStatus = {
			id: 'QuestionsArray',
			initial: 'play',
			states: {
				play: {
					
					...QuestionState
				},
				next: {
					on: {
						CHECK: [
							{
								target: '#game.end',
								cond: (ctx, evt) => {
									ctx.questionIndex += 1;
									ctx.questionPlayTimes = 0
									console.log('#game.end',  ctx.questionIndex >= ctx.questionsCount )
									return ctx.questionIndex >= ctx.questionsCount
								}
							},
							{target: 'play'}
						]
					
					}
				}
			}
		}
		const state = {
			id: 'game',
			initial: 'begin',
			context: {
				questionIndex: 0,
				questionPlayTimes: 0,
				maxQuestionTryTimes: 2,
				questionsCount: this._figurePointRectArray.length,
				questions: this._figurePointRectArray,
			},
			states: {
				begin: {
					
					invoke: {
						src: (ctx) => {
							console.log('game begin');
							if(window.courseware && window.courseware.openOsmoFingerRead) {
								window.courseware.openOsmoFingerRead()
							}
							return new Promise((resolve,reject) => {
								playAudioByUrl(this.data.begin_audio, () => {
									console.log('game begin audio finish');
									resolve()
								})
							});
						},
						onDone:  'playing',
						onError: 'playing'
					}
				},
				playing: {
					entry: (ctx) => {
						console.log('entry play stage');
						cc.assetManager.loadRemote(this.data.playing_audio, (err, audioClip) => {
							cc.audioEngine.playMusic(audioClip, true, 0.8);
						});
						ctx.questions.forEach((block) => {
							block.node.active = false;
						});
					},
					exit: () => {
						console.log('exit play stage');
						cc.audioEngine.stopMusic();
					},
					on: {
						NEXT: 'end'
					},
					// ...QuestionsStates
					...QuestionsArrayStatus
				},
				end: {
					
						entry: (ctx, event) => {
							console.log('game end', ctx, event);
							if(window.courseware && window.courseware.closeOsmoFingerRead) {
								window.courseware.closeOsmoFingerRead()
							}
							playAudioByUrl(this.data.end_audio, () => {
								console.log('game finish');
							})
							// return new Promise((resolve,reject) => {
							// 	setTimeout(() => {
							// 		console.log('hint finish');
							// 		resolve()
							// 	}, 2000)
							// })
						}
					
				},
			}
		};
		const after = {};
		for(let i = 0 ;i  < this._hintsNodeList.length; i++) {
			const t = this._hintsNodeList[i].node;
			const k = this._hintsNodeList[i].after;
			after[k]= {
				actions: () => {
					console.log(k)
					// this.playAni(i, 'normal')
					// cc.tween(t).to(.8, {scale: .3}).to(.8, {scale: .25}).start();
					const dragonDisplay = t.getComponent(dragonBones.ArmatureDisplay);
					dragonDisplay.playAnimation('enlarge', 1);
				} 
			}
		}
		state.states.begin.after = after;

		const gameMachine = createMachine(state);
		window.gameMachine = gameMachine;
		const gameMachineService = interpret(gameMachine).onTransition((state) => {
		// console.log(1, state.value, state.context);
		});
		gameMachineService.start();
		window.gameMachineService = gameMachineService;


	},

	// 生命周期 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()
		});
		window.air = window.air || {}
		if (window.air) {
			window.air.osmoFingerReadCallback = (pos) => {
				if (this.gameMachineService) {
					return;
				}
				// const st = this.gameMachineService.state.value.constructor.name == 'Object' 
				// && this.gameMachineService.state.value['playing']
				// && this.gameMachineService.state.value['playing'].constructor.name == 'Object'
				// && this.gameMachineService.state.value['playing']['play']
				// && this.gameMachineService.state.value['playing']['play'] == 'answer'
				// if (st) {
				// }
				const p = JSON.parse(pos);
				this._lastFingerPosition = {
					pos:{
						x: p.x * 2,
						y: p.y
					},
					dirty: true
				}
			}
		}
	},
	checkInRegion(r) {
		const p = this._lastFingerPosition ? this._lastFingerPosition.pos || {x:0, y:0} : {x:0, y:0};
		const w = p.x > r.x && p.x < (r.x + r.width);
		const h = p.y > r.y && p.y < (r.y + r.height);
		return w && h;

	},

	getData(func) {
		if (window && window.courseware) {
			window.courseware.getData(func, 'scene');
			return;
		}

		const middleLayer = cc.find('middleLayer');
		if (middleLayer) {
			const middleLayerComponent = middleLayer.getComponent('middleLayer');
			middleLayerComponent.getData(func);
			return;
		}

		func(this.getDefaultData());
	},

	getDefaultData() {
		return defaultData;
	},

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


	addPreloadImage() {

		this._imageResList.push({ url: this.data.bgItem.url});

		for (const q of this.data.hotZoneItemArr) {
			if (q.gIdx =='0') {
				this._imageResList.push({ url: q.texPngData.url});
			}

			if (q.gIdx =='1') {
				this._imageResList.push({ url: q.texPngData.url });
			}
			if (q.gIdx =='2') {
				this._imageResList.push({ url: q.pic_url});
			}
		}
	},

	addPreloadAudio() {

		this._audioResList.push({ url: this.data.begin_audio });
		this._audioResList.push({ url: this.data.playing_audio });
		this._audioResList.push({ url: this.data.end_audio });


		for (const q of this.data.hotZoneItemArr) {
			if (q.gIdx =='0') {
				this._audioResList.push({ url: q.audio_url });
			}
		}
	},

	addPreloadAnima() {

	},

	preload() {

		const preloadArr = this._imageResList.concat(this._audioResList).concat(this._animaResList);
		// console.log(preloadArr);
		cc.assetManager.loadAny(preloadArr, null, (f, t, item) => {
			// console.log(f, t, item)
		}, (err, data) => {
			console.log(err, data);
			const ground = cc.find(`Canvas/frame-border/ground`);
			
			const baseRect = this.data.bgItem.rect;
			getSpriteFrimeByUrl(this.data.bgItem.url, (sf) => {
				const gs = ground.getComponent(cc.Sprite);
				gs.spriteFrame = sf;
			});
			for(const block of this.data.hotZoneItemArr) {

				
				if (block.gIdx == '2') {
					const s1 = ((ground.width  / block.imgSizeW) + (ground.height  / block.imgSizeH)) / 2
					const node = new cc.Node();
					node.parent = ground;
					const spr = node.addComponent(cc.Sprite);
					getSpriteFrimeByUrl(block.pic_url, (sf) => {
					  spr.spriteFrame = sf;
					  node.scale = s1;
					})

				}
				if (block.gIdx == '0' || block.gIdx == '1') {
					const n = new cc.Node();
					n.scale = 0.25;
					const db = n.addComponent(dragonBones.ArmatureDisplay);
					
					loadDragonBones(db, {
						tex: block.texPngData.url, 
						atlas: block.texJsonData.url,
						ske: block.skeJsonData.url,
					}).then(({width, height}) => {
						n.width = width;
						n.height = height;	
						n.parent = ground;
						db.playAnimation('normal', 0);
					});
					if (block.gIdx == '0') {
						const rectInfo = {
							node: n,
							audio_url: block.audio_url ,
							rect: {
								x: block.rect.x / baseRect.width,
								y: block.rect.y / baseRect.height,
								width: block.rect.width / baseRect.width,
								height: block.rect.height / baseRect.height,
							}
						};
						this._figurePointRectArray.push(rectInfo);
	
						if (block.labelText) {
							const k = +block.labelText * 1000;
							if(!isNaN(k)) {
								this._hintsNodeList.push({
									node: n,
									after: k
								});
							}
						}
					}
				}
			}
			// console.log(this.data);
			console.log('resource perload finish');

			this.loadEnd();
			if (window && window["air"] && window["air"].hideAirClassLoading) {
				window["air"].hideAirClassLoading();
			}

			cc.debug.setDisplayStats(false);
		});
	},


	loadEnd() {
		this.initData();
		// this.initAudio();
		// this.initView();
		this.initBg();
		// this.initListener();
		this.createStateMachine();
		
	},

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

	// audioBtn: null,
	// initAudio() {
	// 	const audioNode = cc.find('Canvas/res/audio');

	// 	const getAudioByResName = (resName) => {
	// 		return audioNode.getChildByName(resName).getComponent(cc.AudioSource);
	// 	}

	// 	this.audioBtn = getAudioByResName('btn');

	// },


	// initView() {

	// 	// this.initBg();
	// 	// this.initPic();
	// 	// this.initBtn();
	// 	this.initIcon();
	// },

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

	
	

	/*initBtn() {

		this.curPage = 0;
		const bottomPart = cc.find('Canvas/bottomPart');
		bottomPart.zIndex = 5; // 提高层级

		bottomPart.x = bottomPart.parent.width / 2;
		bottomPart.y = -bottomPart.parent.height / 2;

		const leftBtnNode = bottomPart.getChildByName('btn_left');
		//节点中添加了button组件 则可以添加click事件监听
		leftBtnNode.on('click', () => {
			if (!this._cantouch) {
				return;
			}
			if (this.curPage == 0) {
				return;
			}
			this.curPage = 0
			this.leftMove();

			// 游戏结束时需要调用这个方法通知系统作业完成
			onHomeworkFinish();

			cc.audioEngine.play(this.audioBtn.clip, false, 0.8)
		})

		const rightBtnNode = bottomPart.getChildByName('btn_right');
		//节点中添加了button组件 则可以添加click事件监听
		rightBtnNode.on('click', () => {
			if (!this._cantouch) {
				return;
			}
			if (this.curPage == 1) {
				return;
			}

			this.curPage = 1
			this.rightMove();

			cc.audioEngine.play(this.audioBtn.clip, false, 0.5)
		})
	},*/




	// update (dt) {},

























});
