import {
    _decorator, Button,
    Collider,
    Color,
    easing, EPhysicsDrawFlags, game,
    ICollisionEvent,
    Input,
    input,
    instantiate,
    ITriggerEvent,
    Label, lerp,
    Light, MeshRenderer,
    Node,
    ParticleSystem, ParticleSystemComponent,
    PhysicsSystem,
    PointToPointConstraint,
    Prefab,
    RigidBody, Texture2D,
    Tween,
    tween,
    v3,
    Vec3,
} from "cc";
import Scene from "db://assets/Module/Scene";
import { Wall } from "./Wall";
import { _asyncThrottle, sleep } from "../../Utils/Utils";
import GameMgr from "../../GameMgr";
import { AudioMgr } from "../../../core_tgx/base/AudioMgr";
import { mdEvent } from "../../AppTool";
import { BgAndColor } from "./BgAndColor";
import { GuideNode } from "./GuideNode";
import { changeScene } from "../../../Module/UIFast";
import { HomeScene } from "../HomeScene";
import { sendWebNet, WebNetName } from "../../Utils/WebNet/WebNet";
import { MainGame } from "./MainGame";

const { ccclass, property } = _decorator;

@ccclass("GuideGame")
export class GuideGame extends Scene {
    static bundle: string = "MainGame";
    static skin: string = "GuideGame";
    // static group: string[] = ["MainGame"];

    @property(Node) linkPoint: Node = null;
    @property(Node) line: Node = null;

    @property(Node) player: Node = null;
    playerBody: RigidBody = null;
    playerConstraint: PointToPointConstraint = null;


    @property(Node) initWall: Node = null;

    @property(Prefab) wallPrefab: Prefab = null;
    @property(Prefab) wallPrefab2: Prefab = null;

    @property(Prefab) crushPrefab: Prefab = null;

    @property(Light) light: Light = null;

    @property({ type: Label, group: "UI" }) scoreLabel: Label = null;
    @property({ type: Node, group: "UI" }) hitTip: Node = null;

    @property({ type: Node }) bg: Node = null;
    @property({ type: [BgAndColor], visible: true, displayName: `背景和颜色` })
    private bgAndColor: BgAndColor[] = [];


    @property(GuideNode) guideNode: GuideNode = null;

    private _score: number = 0;

    set score(value: number) {
        this._score = value;
        this.scoreLabel.string = value.toString();
    }

    get score() {
        return this._score;
    }

    isTouch = false;

    wallArr: Node[] = [];

    maxZ = 0;
    scoreRadio = 1;

    phyUpdate = true;

    onLoad() {

        PhysicsSystem.instance.autoSimulation = false;

        const playerCollider = this.player.getComponent(Collider);
        playerCollider.on("onCollisionEnter", this.onPlayerCollision, this);
        playerCollider.on('onTriggerEnter', this.onTriggerEnter, this);

        this.mainColor = this.bgAndColor.splice(0, 1)[0];
        this.bg.getComponent(MeshRenderer).material.setProperty("mainTexture", this.mainColor.bg);
        this.light.color = Color.clone(this.mainColor.color);
        this.lightColor = Color.clone(this.mainColor.color);

        this.playerBody = this.player.getComponent(RigidBody);
        this.playerConstraint = this.linkPoint.getComponent(PointToPointConstraint);
    }

    async start() {

        this.wallArr[4] = this.initWall;
        for (let i = 0; i <= 3; i++) {
            this.wallArr[i] = this.createCube(4 - i);
        }

        for (let i = 5; i <= 11; i++) {
            this.wallArr[i] = this.createCube();
            if (i == 11) {
                const wallTs = this.wallArr[i].getComponent(Wall);
                wallTs.createRing(wallTs.dH);
            }
        }

        // await sleep(0.5);
        input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
        input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);
        input.on(Input.EventType.TOUCH_CANCEL, this.onTouchEnd, this);

        this.guideNode.guide4Next.on(Button.EventType.CLICK, this.clickStart, this);
        this.guideNode.show(1);
    }

    onDestroy() {
        input.off(Input.EventType.TOUCH_START, this.onTouchStart, this);
        input.off(Input.EventType.TOUCH_END, this.onTouchEnd, this);
        input.off(Input.EventType.TOUCH_CANCEL, this.onTouchEnd, this);

        this.linkPoint.destroy();
        // this.playerConstraint.connectedBody = null;
        // this.playerConstraint.enabled = false;
    }

    clickStart = _asyncThrottle(async () => {
        if (this.data?.from === "HomeScene") {
            changeScene(HomeScene);
            return;
        }

        // await sendWebNet(WebNetName.stepNewGuide);
        const success = await GameMgr.ins.start();
        if (!success) {
            changeScene(HomeScene);
            return;
        }
        await changeScene(MainGame);
    });

    mainColor: BgAndColor = null;

    randomMainColor() {
        // const index = Math.floor(Math.random() * this.bgAndColor.length);
        // this.mainColor = this.bgAndColor.splice(index, 1, this.mainColor)[0];

        this.mainColor = this.bgAndColor.splice(0, 1)[0];
        this.bgAndColor.push(this.mainColor);
        return this.mainColor;
    }

    isOver: boolean = false;

    async gameOver() {
        if (this.isOver) return;
        this.isOver = true;

        this.phyUpdate = false;

        this.guideNode.show(4);

        // 死了标记新手引导完成
        sendWebNet(WebNetName.stepNewGuide);

    }

    scoreRadioFunc = () => {
        this.scoreRadio = 1;
    }

    async onTriggerEnter(event: ITriggerEvent) {
        const { otherCollider, selfCollider } = event;

        const otherName = otherCollider.node.name;

        if (otherName == "光幕") {
            otherCollider.node.active = false;
            this.changeMainColor();
        } else if (otherName == "圆环") {

            await new Promise<void>((resolve) => {
                this.phyUpdate = false;
                this.guideNode.show(3);
                this.guideNode.guide3Next.once(Button.EventType.CLICK, () => {
                    this.phyUpdate = true;
                    this.guideNode.hide();
                    if (this.data?.from !== "HomeScene") {
                        // sendWebNet(WebNetName.stepNewGuide);
                    }

                    // this.scheduleOnce(() => {
                    //     this.gameOver();
                    // }, 10);

                    resolve();
                });
            });

            otherCollider.node.active = false;
            this.scoreRadio = 2;
            this.unschedule(this.scoreRadioFunc);
            this.scheduleOnce(this.scoreRadioFunc, 5);
            tween(this.hitTip)
                .set({ active: true })
                .delay(2)
                .set({ active: false })
                .start();

            const crushNode = instantiate(this.crushPrefab);
            this.node.addChild(crushNode);
            crushNode.setPosition(otherCollider.node.worldPosition);
            const particleSys = crushNode.getComponent(ParticleSystem);
            particleSys.play();
            this.scheduleOnce(() => {
                crushNode.destroy();
            }, particleSys.duration);
        }
    }

    onPlayerCollision(event: ICollisionEvent) {
        if (this.isOver) return;

        const { otherCollider, selfCollider } = event;

        const otherGroup = otherCollider.getGroup();

        if (otherGroup === PhysicsSystem.PhysicsGroup['Wall']) {
            // 死了
            this.playerBody.enabled = false;
            this.player.active = false;

            const crushNode = instantiate(this.crushPrefab);
            this.node.addChild(crushNode);
            crushNode.setPosition(this.player.position);
            const particleSys = crushNode.getComponent(ParticleSystem);
            particleSys.play();
            this.scheduleOnce(() => {
                crushNode.destroy();
            }, particleSys.duration);

            this.gameOver();
        }

    }

    lightTween: Tween<any> = null;
    lightColor: Color = null;

    changeMainColor() {
        this.randomMainColor();
        const { bg, color } = this.mainColor;

        this.bg.getComponent(MeshRenderer).material.setProperty("mainTexture", bg);
        this.lightTween?.removeSelf();
        this.lightTween = tween({ radio: 0 })
            .to(1, { radio: 1 }, {
                easing: easing.quadInOut,
                onUpdate: (target, ratio) => {
                    this.lightColor.lerp(color, ratio);
                    this.light.color = this.lightColor;
                }
            })
            .start();
    }

    createCube(z = this.wallArr[this.wallArr.length - 1].position.z - 1) {
        const singular = z % 2 == 0;
        const newGroup = instantiate(singular ? this.wallPrefab : this.wallPrefab2);
        this.node.addChild(newGroup);
        newGroup.setPosition(v3(0, 0, z));
        newGroup.getComponent(Wall).resetGuide();
        return newGroup;
    }

    onTouchStart(event: any) {

        if (this.guideNode.guideShow && this.guideNode.guideIndex > 1) {
            return;
        }

        if (this.isOver) return;

        this.isTouch = true;

        AudioMgr.ins.playOneShot("audio/点击音效", {
            bundleName: "common",
        });

        this.line.active = true;

        const pPos = this.player.position;
        const targetZ = pPos.z - 0.5;
        const index = this.wallArr[0].position.z - Math.round(targetZ);
        const y = this.wallArr[index].getComponent(Wall).topY;

        const linkPos = v3(0, y, targetZ);
        this.linkPoint.setPosition(linkPos);

        // 计算角度
        const dir = Vec3.subtract(new Vec3(), linkPos, pPos);
        const angle = Math.atan(dir.z / dir.y) * 180 / Math.PI;
        this.player.setRotationFromEuler(angle, 0, 0);

        // 重新设置连接点
        const constraintY = Vec3.distance(pPos, linkPos);
        this.playerConstraint.pivotB = v3(0, constraintY, 0);
        this.playerConstraint.enabled = true;

        const velocityMultiplier = lerp(0, 1, this.getDifficultyRatio());

        const linear = v3();
        this.playerBody.getLinearVelocity(linear);
        linear.multiplyScalar(velocityMultiplier);
        this.playerBody.setLinearVelocity(linear);

        const angular = v3();
        this.playerBody.getAngularVelocity(angular);
        angular.multiplyScalar(velocityMultiplier);
        this.playerBody.setAngularVelocity(v3());

        // 新手引导
        if (this.guideNode.guideIndex == 1) {
            this.guideNode.hide();
            if (this.data?.from !== "HomeScene") {
                // sendWebNet(WebNetName.stepNewGuide);
            }
            this.scheduleOnce(() => {
                this.phyUpdate = false;
                this.guideNode.show(2);
                this.guideNode.guide2Next.on(Button.EventType.CLICK, () => {
                    this.guideNode.hide();
                    this.phyUpdate = true;
                    if (this.data?.from !== "HomeScene") {
                        // sendWebNet(WebNetName.stepNewGuide);
                    }
                });
            }, 0.65);
        }
    }

    onTouchEnd(event: any) {
        if (this.isOver) return;
        if (!this.isTouch) return;

        this.isTouch = false;
        this.line.active = false;
        this.playerConstraint.enabled = false;
    }

    checkFrame = 0;

    checkWall() {
        this.checkFrame = 0;
        const pPos = this.player.position;
        const pz = Math.round(pPos.z);
        const index = this.wallArr[0].position.z - pz;

        const createCount = index - 4;
        for (let i = 0; i < createCount; i++) {
            const wall = this.wallArr.shift();
            wall.setPosition(0, Math.random(), this.wallArr[this.wallArr.length - 1].position.z - 1);
            this.wallArr.push(wall);
            const wallTs = wall.getComponent(Wall);
            if (this.guideNode.guideIndex == 3) {
                wallTs.resetDeath();
            } else {
                wallTs.resetGuide();
            }
        }
    }

    updateScore(addScore) {
        this.score += ~~((addScore * 15) * this.scoreRadio);
        if (this.score > 9999) {
            this.score = 9999;
            this.gameOver();
        }
    }

    /**
     * 获取难度比例，根据分数返回难度比例，最大到5000，难度最大
     * @returns {number} 返回计算后的难度比例值
     */
    getDifficultyRatio(): number {
        return Math.min(this.score, 5000) / 5000;
    }

    protected lateUpdate(dt: number) {

        if (!this.phyUpdate) return;

        PhysicsSystem.instance.physicsWorld.syncSceneToPhysics();

        // PhysicsSystem.instance.fixedTimeStep = dt;
        // PhysicsSystem.instance.update(dt);
        PhysicsSystem.instance.step(1 / 60, dt);

        PhysicsSystem.instance.physicsWorld.emitEvents();
        PhysicsSystem.instance.physicsWorld.syncAfterEvents();
    }

    update(dt: number) {

        if (this.isOver) return;

        const pz = -this.player.position.z;
        const addScore = pz - this.maxZ;

        if (pz > 0) {
            this.maxZ += addScore;
            this.updateScore(addScore);
        }

        this.checkFrame++;
        // 检测是否需要生成墙
        if (this.checkFrame >= 20) {
            this.checkWall();
        }

        if (this.phyUpdate && this.isTouch) {
            const lineScale = Vec3.distance(this.player.position, this.linkPoint.position);
            this.line.setScale(1, lineScale / 2, 1);

            this.playerBody.applyForce(v3(0, 0, -10));
        } else {
            // this.playerBody.applyForce(v3(0, 0, -10));
        }

    }

}
