import MoveObjcet from "./MoveObject";
import Collider, {CircleCollider, ColliderGroup} from "../Phycics/Collider";
import {MConfigs} from "../Global/MConfigs";
import {getBallScore, getProp} from "../Global/GUtils";
import {PoolElement} from "../Component/Pool";
import {MConst} from "../Global/MConst";
import Drop from "./Drop";
import Bullet from "./Bullet";
import {MUtils} from "../Global/MUtils";
import SoundMgr from "../Mgr/SoundMgr";
import {DataMgr} from "../Mgr/DataMgr";
import GuideMgr from "../Mgr/GuideMgr";
import MTimer from "../Global/MTimer";
import {getTexture} from "../utils";
import {props} from "../../props";

let tempPower: number = null;
let tempIndexOffset: number = null;
const imageNames = [
	"39843f75-8caa-4cee-bff5-91fb759b691b",
	"bd94b3e6-3c99-490f-95ef-ca0c056d7727",
	"d8eab9fc-104e-4b39-88d6-455ed8632703",
	"48f98d84-d30e-4dfe-aa92-c45bde5cefd8",
	"8d42fd9e-907b-4587-9a6f-a634909b8b8a",
];

const textureSize = {
	width: 210,
	height: 213
};

export default class Ball extends MoveObjcet implements PoolElement {
	private colorIndex = 0;
	private sizeIndex = 0;
	private bitmap: engine.Sprite = null;
	public static textures: engine.Texture[] = [];
	private labelScore: engine.BitmapText = null;
	// private labelScoreShadow: engine.Label = null;
	private scaleRatio: number = 1;
	private initScore: number = null;
	private initColorIndex: number = 0;
	public collider: CircleCollider = null;
	private isBornStage = false;
	public poolKey: string = null;

	private _score = 0;
	public get score() {
		return this._score;
	}

	public set score(v: number) {
		if (v < 0) v = 0;
		//分数标签更新
		if (this._score != v) {
			this.scoreUpdateFlag = true;
		}

		this._score = v;
	}

	// private static ballTextures: engine.Texture[] = [];
	/* public static loadTextures() {
			for (let i in imageNames) {
					Ball.ballTextures[i] = getTexture(imageNames[i]);
			}
	} */

	private onScoreIsZero() {
		if (GuideMgr.instance.guideFlag == true) {
			this.drop();
		} else {
			if (this.sizeIndex > 0) {
				this.split();
			} else {
				this.drop();
			}
		}

		DataMgr.game._playBoomEffect(this.position, this.scaleRatio);
		SoundMgr.instance.playEffect("boom");
		DataMgr.game._pool.ball.recycle(this.poolKey, this);
	}

	constructor(sizeIndex: number) {
		super();
		//获取配置
		let scaleRatio = MConfigs.size[sizeIndex]; //整体缩放系数

		//创建图像
		const bitmapWidth = textureSize.width * scaleRatio;
		const bitmapHeight = textureSize.height * scaleRatio;
		this.bitmap = new engine.Sprite();
		this.addChild(this.bitmap);
		this.bitmap.width = bitmapWidth;
		this.bitmap.height = bitmapHeight;
		this.anchorX = bitmapWidth / 2;
		this.anchorY = bitmapHeight / 2;
		this.bitmap.x = -bitmapWidth / 2;
		this.bitmap.y = -bitmapHeight / 2;

		//创建文字
		let labelScore = new engine.BitmapText();
		labelScore.font = props.fontName;
		labelScore.scaleX = labelScore.scaleY = scaleRatio;
		this.addChild(labelScore);

		//添加碰撞器
		let collider = this.addComponent(CircleCollider) as CircleCollider;
		collider.group = ColliderGroup.Ball;
		this.collider = collider;
		collider.setData(0, 0, bitmapHeight / 2);

		//初始化属性
		this.scaleRatio = scaleRatio;
		this.sizeIndex = sizeIndex;
		this.labelScore = labelScore;
	}

	init(colorIndex: number, direction: 1 | -1, score: number): Ball {
		this.colorIndex = colorIndex;
		this.initColorIndex = colorIndex;
		this.bitmap.texture = getTexture(imageNames[colorIndex]);

		this.initScore = score;
		this.score = score;
		this.physics.rotateVelocity = direction * MConst.BallRotateSpeed * Math.pow(1 / this.scaleRatio, 0.5);
		return this;
	}

	startBornStage(dir: 1 | -1) {
		this.isBornStage = true;
		if (dir == 1) {
			this.x = 0 - this.width / 2 - 10;
		} else if (dir == -1) {
			this.x = MConst.DesignResolution.width + this.width / 2 + 10;
		}
		this.y = MConst.BallInitPosY;

		this.physics.velocity.x = this.getRandomVelocityX(dir) + 1 * dir;
		this.dir = dir;
		this.physics.onMoved = this.onBornStageMoved.bind(this)
	}

	private dir: 1 | -1 = 1;

	private onBornStageMoved(owner: Ball) {
		if (this.dir == 1) {
			if (this.x > this.width / 2) {
				this.startGravityStage(this.dir);
				this.physics.onMoved = null;
			}
		} else if (this.dir == -1) {
			if (this.x < MConst.DesignResolution.width - this.width / 2) {
				this.startGravityStage(this.dir);
				this.physics.onMoved = null;
			}
		}
	}

	private getRandomVelocityX(direction: 1 | -1) {
		return direction * MConst.BallVelocityX * (1 + ((1 / this.scaleRatio) - 1) * MUtils.random(0, MConst.BallVelocityXRandomFactor));
	}

	startGravityStage(direction: 1 | -1) {
		this.isBornStage = false;
		this.physics.velocity.x = this.getRandomVelocityX(direction);
		this.physics.acceleration.y = MConst.Gravity;
	}

	onCollisionEnter(other: Collider) {
		if (other.group == ColliderGroup.Bullet) {
			tempPower = (other.owner as Bullet).power;
			this.score = this.score - tempPower;
			DataMgr.game._score += tempPower;
		}

		if (other.group == ColliderGroup.Ground) {
			this.physics.velocity.y = -(MConst.BallVelocityY * (1 + ((1 / this.scaleRatio) - 1) * MUtils.random(0, MConst.BallVelocityYRandomFactor)));

			//播放灰尘动画
			const clip = DataMgr.game._createAnimation("duang");
			clip.x = this.x - 140 * this.scaleRatio;
			clip.y = this.y - 50 * this.scaleRatio;
			clip.scaleX = clip.scaleY = this.scaleRatio;
			clip.play();
			//判断是否会震动地面
			if (this.sizeIndex >= MConfigs.size.length - 2) {
				DataMgr.game._shake();
				SoundMgr.instance.playEffect("dong");
			}
		}

		if (other.group == ColliderGroup.Wall && !this.isBornStage) {
			this.physics.velocity.x = -this.physics.velocity.x;
			this.physics.rotateVelocity = -this.physics.rotateVelocity;
		}
	}

	onCollisionStay(other: Collider) {
		if (other.group == ColliderGroup.Wall && !this.isBornStage) {
			let dir: 1 | -1 = other.owner.x < 0 ? 1 : -1;
			this.physics.velocity.x = dir * Math.abs(this.physics.velocity.x);
			this.physics.rotateVelocity = dir * Math.abs(this.physics.rotateVelocity);

		}
	}

	/**@inheritdoc */
	onElementRecycle() {
		this.visible = false;
		this.physics.velocity.y = 0;
		this.physics.velocity.x = 0;
		this.physics.acceleration.y = 0;
		this.physics.acceleration.x = 0;
		this.disableAllComponents();

	}

	onElementInit() {
		this.visible = true;
		this.enableAllComponents();
	}

	private split() {
		let sizeIndex = this.sizeIndex - 1;
		let score = Math.ceil(this.initScore / 2 * (Math.random() * 0.4 + 0.8));
		let colorIndex = Math.max(this.initColorIndex - 1, 0);

		let callback = (direction: 1 | -1) => {
			let ball = DataMgr.game._pool.ball.spwan(sizeIndex).init(colorIndex, direction, score);
			ball.x = this.x;
			ball.y = this.y;
			ball.startGravityStage(direction);
			ball.physics.velocity.y = -MConst.BallSplitVelocityY;
		};

		callback(1);
		callback(-1);
	}

	private scoreUpdateFlag = false;

	public updateScoreLabel() {
		if (this.scoreUpdateFlag == true) {
			const labelScore = this.labelScore;
			const score = this.score;
			if (score >= 1000) {
				labelScore.text = (Math.floor(score / 100) / 10).toString() + "k";
			} else {
				labelScore.text = score.toString();
			}

			labelScore.x = -labelScore.width / 2;
			labelScore.y = -labelScore.height / 2;

			this.scoreUpdateFlag = false;

			//判断是否需要更改颜色
			/* if (this.initScore == null) return;
			if (score > 0) {
					tempIndexOffset = Math.floor((this.initScore - score) / this.initScore / (1 / (this.initColorIndex + 1)));
					if (this.initColorIndex - tempIndexOffset != this.colorIndex) { //目标颜色和当前颜色不一致
							//更新颜色
							this.colorIndex = this.initColorIndex - tempIndexOffset;
							this.bitmap.texture = Ball.ballTextures[this.colorIndex];
					}
			} else {
					this.onScoreIsZero();
			} */

			if (this.score <= 0) {
				this.onScoreIsZero();
			}
		}
	}

	private drop() {
		//掉落数
		let index = 1;
		//根据子弹分数判断索引
		let bulletScore = DataMgr.game.bulletScore;
		if (bulletScore <= 30) index = 0;
		else if (bulletScore > 30 && bulletScore <= 70) index = 1;
		else if (bulletScore > 70) index = 2;
		//根据索引获取配置
		let config: {
			num: number,
			factor: object
		} = MConfigs.dropPool[index];

		let keys = Object.keys(config.factor);
		let values = keys.map(e => config.factor[e]);
		let dropIds: number[] = getProp(keys, values, config.num);

		let drops: Drop[] = [];
		for (let id of dropIds) {
			drops.push(DataMgr.game._pool.drop.spwan(id.toString()));
		}

		let dir = this.x > MConst.DesignResolution.width / 2 ? -1 : 1;

		for (let i = 0; i < drops.length; i++) {
			let drop = drops[i];
			drop.x = this.x - drop.bitmap.width / 2;
			drop.y = this.y - drop.bitmap.height / 2;
			let offsetRatio = (i - 1) + (2 - (drops.length - 1));
			let x = MConst.DropVelocityX.x + offsetRatio * MConst.DropVelocityX.offset;

			x *= MUtils.random(1 - MConst.DropRandomFactor, 1 + MConst.DropRandomFactor);
			drop.physics.velocity.x = dir * x;
			drop.physics.velocity.y = -(x * 5 * MUtils.random(0.9, 1.1));

			if (GuideMgr.instance.guideFlag && i == 1) {
				MTimer.setFrameTimer(20, () => {
					GuideMgr.instance.runGuide(1, drop.x, drop.y, true);
				});
			}
		}
	}
}