import {
    _decorator, Animation, assetManager, AssetManager, CircleCollider2D,
    Collider2D,
    Component,
    Contact2DType, instantiate, IVec2Like, math,
    Node,
    PhysicsGroup,
    Prefab,
    Sprite, SpriteAtlas,
    SpriteFrame, Tween,
    tween, UITransform,
    v2,
    v3, Vec2,
    Vec3,
} from "cc";
import { Global, SkinName } from "./Global";
import { isIntersect } from "./utils/uitl";
import { accEffectPool, bodyPool } from "./Manager/CommonPool";
import { PropBase } from "./Props/PropBase";
import { FoodManger } from "./Manager/FoodManger";
import { ECard, EPropType } from "./Common/Enums";
import { Player } from "./Player";
import gameStore from "../../store/gameStore";

const { ccclass, property } = _decorator;

export interface IInitConfig {
    nickName: string,
    x?: number;
    y?: number;
    angle?: number;
    skinName?: string;
    scale?: number;
    bodyCount?: number;
    initEnergy?: number,
    tag?: number;
}

@ccclass("Snake")
export class Snake extends Component {

    static tag: number = 0;
    static getTag() {
        return Snake.tag++;
    }

    @property({ type: Node, displayName: "头部" }) head: Node = null;

    @property(Prefab) bodyPrefab: Prefab = null;
    @property(Prefab) accEffectPrefab: Prefab = null;
    @property(Prefab) magnetEffectPrefab: Prefab = null;

    cardMap: Map<ECard, number> = new Map<ECard, number>();

    private imgHead: SpriteFrame = null;
    private imgBodyArr: SpriteFrame[] = [];
    private imgTail: SpriteFrame = null;
    nickName: string;
    skinName: string;

    bodyArr: Node[] = [];

    // 吃东西的范围
    eatCollider: CircleCollider2D = null;
    eatPropCollider: CircleCollider2D = null;

    // 加速效果
    accEffectNode: Node = null;
    accEffectArr: Node[] = [];

    // 磁铁效果
    magnetEffectNode: Node = null;

    isLife: boolean = false;

    // 福袋个数
    protected _luckNum = 0;
    get luckNum() {
        return this._luckNum;
    }

    set luckNum(value: number) {
        this._luckNum = value;
    }

    protected _scale: number = 0.2;
    get scale() {
        return this._scale;
    }
    set scale(value: number) {
        this._scale = value;
    }

    speed: number = 300;
    energy: number = 0;
    tag: number = 0;

    // 位置相关
    private ready: boolean = false;


    private _length: number = 0;
    get length() {
        return this._length;
    }

    set length(value: number) {
        this._length = value;
        this?.node?.emit("updateLength", value);
    }

    get radius() {
        return this.scale * 29;
    }

    onLoad() {
        this.accEffectNode = new Node("accEffectNode");
        this.node.addChild(this.accEffectNode);

        this.magnetEffectNode = instantiate(this.magnetEffectPrefab);
        this.head.addChild(this.magnetEffectNode);
        this.magnetEffectNode.active = false;

        this.eatCollider = this.head.getChildByName("吃饭范围").getComponent(CircleCollider2D);
        this.eatPropCollider = this.head.getChildByName("吃道具范围").getComponent(CircleCollider2D);
    }

    onDestroy() {
    }


    // 初始化方法
    public async init(config: IInitConfig) {

        this.bodyArr.forEach((body) => {
            body.removeFromParent();
            bodyPool.put(body);
        });

        const {
            nickName,
            x = 0, y = 0, angle = 0, scale = 0.5,
            skinName = SkinName.sp_decoration_default,
            initEnergy = 5,
            tag = Snake.getTag(),
        } = config;

        this.setSkin(skinName);

        this.nickName = nickName;
        this.skinName = skinName;
        this.ready = false;
        this.energy = 0;
        this.bodyArr.length = 0;
        this.scale = scale;
        this.tag = tag;


        const hw = this.imgHead.originalSize.width;
        const bw = this.imgBodyArr[0].originalSize.width;

        // 设置头部
        this.head.angle = angle;
        this.head.setPosition(x, y);
        this.head.setScale(scale, scale);
        this.head.getComponent(Sprite).spriteFrame = this.imgHead;
        this.head.getComponent(UITransform).anchorX = (bw / 2) / hw;

        // 创建尾巴节点
        const tile = bodyPool.get() || instantiate(this.bodyPrefab);
        tile.angle = angle;
        tile.setPosition(x, y);
        tile.setScale(scale, scale);

        if (this.imgTail) {
            tile.getComponent(Sprite).spriteFrame = this.imgTail;
            const tw = this.imgTail.originalSize.width;
            tile.getComponent(UITransform).anchorX = (bw / 2) / tw;
        } else {
            tile.getComponent(Sprite).spriteFrame = this.imgBodyArr[0];
        }

        tile.getComponent(Collider2D).tag = this.tag;
        this.node.insertChild(tile, 0);
        this.bodyArr.push(tile);

        this.length = 2;

        // 创建身体节点
        this.addEnergy(initEnergy);

        this.isLife = true;
        this.ready = true;
    }

    setSkin(skinName: string) {
        const skin = assetManager.getBundle("MainGame").get(`skin/${skinName}`, SpriteAtlas);
        this.imgHead = skin.getSpriteFrame("head");

        let bodyIndex = 1;
        while (bodyIndex) {
            const bodyImg = skin.getSpriteFrame(`body${bodyIndex}`);
            if (bodyImg) {
                this.imgBodyArr.push(bodyImg);
                bodyIndex++;
            } else {
                bodyIndex = 0;
            }
        }
        this.imgTail = skin.getSpriteFrame("tail");
    }

    onEnable() {
        const collider = this.head.getComponent(Collider2D);
        collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginHead, this);

        this.eatCollider.on(Contact2DType.BEGIN_CONTACT, this.onBeginEat, this);
        this.eatPropCollider.on(Contact2DType.BEGIN_CONTACT, this.onBeginEatProp, this);
    }

    onDisable() {
        const collider = this.head.getComponent(Collider2D);
        collider.off(Contact2DType.BEGIN_CONTACT, this.onBeginHead, this);

        this.eatCollider.off(Contact2DType.BEGIN_CONTACT, this.onBeginEat, this);
        this.eatPropCollider.off(Contact2DType.BEGIN_CONTACT, this.onBeginEatProp, this);
    }

    // 碰撞检测
    private onBeginHead(selfCollider: Collider2D, otherCollider: Collider2D) {
        if (otherCollider.group === PhysicsGroup["Body"] && otherCollider.tag != this.tag) {

            const playerTs = otherCollider?.node?.parent?.getComponent(Player);
            if (playerTs) {
                gameStore.gameInfo.killNum++;
            }

            this.death();
        }
    }

    onBeginEat(selfCollider: Collider2D, otherCollider: Collider2D) {
        if (otherCollider.group === PhysicsGroup["Prop"]) {

            const propTs = otherCollider.getComponent(PropBase);
            if (propTs && propTs.canEaten && propTs.tag == EPropType.FOOD) {
                this.eatProp(propTs);
            }
        }
    }

    onBeginEatProp(selfCollider: Collider2D, otherCollider: Collider2D) {
        if (otherCollider.group === PhysicsGroup["Prop"]) {

            const propTs = otherCollider.getComponent(PropBase);
            if (propTs && propTs.canEaten && propTs.tag != EPropType.FOOD) {
                this.eatProp(propTs);
            }
        }
    }

    eatProp(propTs: PropBase) {
        propTs.canEaten = false;
        // 食物吃掉的动画
        Tween.stopAllByTarget(propTs.node);
        tween(propTs.node)
            .to(0.188, {
                position: this.head.getPosition(),
                scale: v3(0, 0)
            })
            .call(() => {
                if (this.isLife) {
                    propTs.beEaten(this);
                }
                propTs.recycle();
            })
            .start();
    }

    addCard(type: ECard) {
        if (!this.cardMap.has(type)) {
            this.cardMap.set(type, 0);
        }
        this.cardMap.set(type, this.cardMap.get(type) + 1);
        this.checkCard(type);
    }

    checkCard(type: ECard) {

    }

    // 上次生长富余的能量
    private lastRemaining = 0;

    /**
     * 加能量
     */
    addEnergy(value: number) {
        this.energy += value;
        const growthThreshold = Math.floor(4 * this.scale);


        value += this.lastRemaining;

        while (value >= growthThreshold) {
            value -= growthThreshold;
            if (this.scale < 1) {
                this.scale += 0.005;
            }
            this.grow();
        }

        this.lastRemaining = value;

        // this.speed = 600 * this.scale;
    }

    /**
     * 生长
     */
    private grow() {

        if (!this.isValid) return;

        this.length += 1;

        let len = this.bodyArr.length;
        if (this.imgTail) len -= 1;

        const newBody = bodyPool.get() || instantiate(this.bodyPrefab);

        const pre = this.bodyArr[len - 1] || this.head;

        newBody.angle = pre.angle;
        newBody.setPosition(pre.position);
        newBody.setScale(this.scale, this.scale);
        this.node.insertChild(newBody, 1);

        newBody.getComponent(UITransform).anchorX = 0.5;

        newBody.getComponent(Sprite).spriteFrame = this.imgBodyArr[(this.length - 2) % this.imgBodyArr.length];

        newBody.getComponent(Collider2D).tag = this.tag;

        // newBody.active = isIntersect(
        //     newBody.getPosition(),
        //     this.head.getPosition(),
        //     this.vw,
        //     this.vh
        // );

        this.bodyArr.splice(len, 0, newBody);
    }

    isFast = false;
    positions: IVec2Like[] = []; // 存储历史位置点
    private readonly HISTORY_LENGTH = 10; // 增加历史点数量
    private readonly SEGMENT_SPACING = 6.3; // 增加节点间距

    moveTime = 1 / 60;
    totalTime = 0;
    moveScale = 1;

    onUpdate(dt: number) {
        let moveScale = this.moveScale;
        if (this.isFast) {
            moveScale += 1;
        }

        this.totalTime += dt * moveScale;
        while (this.totalTime >= this.moveTime) {
            this.totalTime -= this.moveTime;
            this.move(this.moveTime);
            this.updateAccEffect();
        }
    }

    protected move(dt: number) {
        if (!this.ready || !this.isLife) {
            return;
        }

        const bodyLen = this.bodyArr.length;

        const headAngle = this.head.angle;

        // 更新头部位置
        const newHeadPos = this.getVelocity(headAngle)
            .multiplyScalar(dt * this.speed)
            .add2f(this.head.position.x, this.head.position.y);

        this.head.setPosition(newHeadPos.x, newHeadPos.y);
        const flipY = headAngle > 90 && headAngle < 270;
        this.head.setScale(this.scale, flipY ? -this.scale : this.scale);
        // this.head.setSiblingIndex(bodyLen - 1);

        const space = this.SEGMENT_SPACING * this.scale;

        // 存储历史位置
        this.positions.unshift(newHeadPos);
        // 确保历史位置点足够多，以容纳所有身体节点
        const requiredLength = this.bodyArr.length * space + 1;
        if (this.positions.length > Math.max(requiredLength, this.HISTORY_LENGTH)) {
            this.positions.pop();
        }

        // 更新身体节点位置
        for (let i = 0; i < bodyLen; i++) {
            const body = this.bodyArr[i];

            // 为每个节点计算一个固定的偏移量
            const offset = (i + 1) * (~~space);

            // 确保不会超出历史位置数组范围
            if (offset < this.positions.length) {
                const targetPos = this.positions[offset];

                // 计算角度
                if (offset > 0) {
                    const prevPos = this.positions[offset - 1];
                    body.angle = Math.atan2(
                        targetPos.y - prevPos.y,
                        targetPos.x - prevPos.x
                    ) * 180 / 3.1415927;
                }

                body.setPosition(targetPos.x, targetPos.y);
                body.setScale(this.scale, this.scale);
                // body.setSiblingIndex(bodyLen - i - 1);

                // body.active = isIntersect(
                //     targetPos,
                //     this.head.getPosition(),
                //     this.vw,
                //     this.vh
                // );
            }
        }

        // 边界检查
        const mapHalfWidth = Global.MAP_WIDTH / 2;
        const mapHalfHeight = Global.MAP_HEIGHT / 2;
        if (
            newHeadPos.x <= -mapHalfWidth
            || newHeadPos.x >= mapHalfWidth
            || newHeadPos.y <= -mapHalfHeight
            || newHeadPos.y >= mapHalfHeight
        ) {
            this.death();
        }

    }

    /**
     * 加速特效
     */
    updateAccEffect() {
        if (!this.isFast || !this.isLife) {
            this.accEffectNode.active = false;
            return;
        }

        this.accEffectNode.active = true;

        const count = this.bodyArr.length / 4 >> 0;
        for (let i = this.accEffectArr.length - 1; i < count; i++) {
            const accEffect = accEffectPool.get() || instantiate(this.accEffectPrefab);
            this.accEffectNode.addChild(accEffect);
            this.accEffectArr.push(accEffect);
        }

        const node = this.accEffectArr[0];
        node.setPosition(this.head.position);
        node.angle = this.head.angle;
        node.setScale(this.scale, this.scale);

        const len = this.accEffectArr.length;
        for (let i = 1; i < len; i++) {
            const node = this.accEffectArr[i];
            const body = this.bodyArr[i * 4 - 1];
            node.setPosition(body.position);
            node.angle = body.angle;
            node.setScale(this.scale, this.scale);
        }

    }

    /**
     * 死亡
     */
    death() {
        if (!this.isLife) return;

        this.positions.length = 0;
        this.isLife = false;
        this.node.removeFromParent();
        this.clearInvincible();

        const len = this.bodyArr.length;
        const foodArr = this.bodyArr.map((body) => {
            body.removeFromParent();
            bodyPool.put(body);

            return {
                x: body.position.x + math.randomRange(-5, 5),
                y: body.position.y + math.randomRange(-5, 5),
                energy: ~~(this.energy / len),
            };
        });
        this.bodyArr.length = 0;

        FoodManger.ins.initFoods(foodArr);
    }

    /**
     * 获得方向
     */
    getVelocity(angle = this.head.angle) {
        const radian = angle / 180 * Math.PI;
        return v2(Math.cos(radian), Math.sin(radian));
    }


    /****************************** 磁铁 ******************************/
    magnetTw: Tween<any> = null;
    useMagnet() {
        this.clearMagnet();
        this.magnetEffectNode.active = true;
        this.magnetEffectNode.getComponent(Animation).play();
        this.eatCollider.radius = 240;
        this.magnetTw = tween(this)
            .delay(10)
            .call(() => {
                this.clearMagnet();
            })
            .start();
    }

    // flushMagnet() {
    //     FoodManger.ins.node.children.forEach((child) => {
    //         const propTs = child.getComponent(PropBase);
    //         if (propTs.canEaten) {
    //             propTs.canEaten = false;
    //             Tween.stopAllByTarget(child);
    //             tween(child)
    //                 .to(0.5, {
    //                     position: this.head.getPosition(),
    //                 })
    //                 .call(() => {
    //                     if (this.isLife) {
    //                         propTs.beEaten(this);
    //                     }
    //                     propTs.recycle();
    //                 })
    //                 .start();
    //         }
    //     });
    // }

    clearMagnet() {
        this.magnetTw?.removeSelf();
        this.magnetEffectNode.active = false;
        this.magnetEffectNode.getComponent(Animation).stop();
        this.eatCollider.radius = 65;
    }

    /****************************** 护盾 ******************************/

    /**
     * 护盾时间
     * 假如有两个护盾同时生效，则取时间大的，正是因为这样，才设计成数字
     */
    _invincibleTime: number = 0;
    get invincibleTime() {
        return this._invincibleTime;
    }

    set invincibleTime(value: number) {
        this._invincibleTime = Math.max(this._invincibleTime, value);
    }

    clearInvincible() {
        this._invincibleTime = 0;
    }



}