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";
import { Target } from "./Components/Target";
import { AISnake } from "./AISnake";

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;
}

const skinCache = {};

@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;
    @property(Prefab) defenseEffectPrefab: 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;

    //护盾效果
    defenseEffectNode: Node = null;

    //双倍经验
    doubleStatus: boolean = false;

    isLife: boolean = false;

    isComposed: boolean = false;

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

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

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

    speed: number = 300;

    _energy: number = 0;
    get energy() {
        return this._energy;
    }

    set energy(value: number) {
        this._energy = value;
    }

    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.defenseEffectNode = instantiate(this.defenseEffectPrefab)
        this.head.addChild(this.defenseEffectNode);
        this.defenseEffectNode.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 = 1,
            skinName = SkinName.sp_decoration_default,
            initEnergy = 50,
            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.name = "tail";
        tile.angle = angle;
        tile.setPosition(x, y);
        tile.setScale(scale, scale);

        tile.getComponent(Sprite).spriteFrame = this.imgTail;
        const tw = this.imgTail.originalSize.width;
        tile.getComponent(UITransform).anchorX = (bw / 2) / tw;

        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) {
        if(!skinCache[skinName]){
            skinCache[skinName] = assetManager.getBundle("MainGame").get(`skin/${skinName}`, SpriteAtlas);
        }

        const skin = skinCache[skinName];

        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") || this.imgBodyArr[0];
    }

    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) {

            if (this.invincibleTime > 0) {
                this.breakDefense()
                return;
            }

            if ((otherCollider?.node?.parent?.getComponent(Snake)?.["initFlag"])){
                return;
            }

            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) {
                if (propTs.tag == EPropType.CARD_A || propTs.tag == EPropType.CARD_B || propTs.tag == EPropType.CARD_C) {
                    if (this.isComposed) {
                        /**合成中不吃 */
                        return
                    }
                }
                this.eatProp(propTs);
            }
        }
    }

    eatProp(propTs: PropBase) {
        propTs.canEaten = false;
        propTs.node["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(cardType: ECard) {

    }

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

    /**
     * 加能量
     * 暂定加长/双倍道具卡效果不叠加
     */
    addEnergy(value: number, useProps: boolean = false) {
        value = this.doubleStatus && !useProps ? value * 2 : value
        this.energy += value
        const growthThreshold = Math.floor(12 * this.scale);

        value += this.lastRemaining;

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

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

    /**
     * 快速生长
     */

    fastGrow(energy: number) {
        this.addEnergy(energy)
        // for (let i = 0; i < time; i++) {
        //     this.grow();
        // }
    }

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

        if (this.length > 180) {
            return;
        }

        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(999999, 999999);
        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;
    isSpeed = 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);

        const space = this.SEGMENT_SPACING * this.scale;

        // 存储历史位置
        this.positions.unshift(newHeadPos);
        // 确保历史位置点足够多，以容纳所有身体节点
        const requiredLength = this.bodyArr.length * space + 1;
        if (this.positions.length > requiredLength) {
            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.active = isIntersect(
                //     targetPos,
                //     this.head.getPosition(),
                //     this.vw,
                //     this.vh
                // );
            }
        }

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

    }

    /**
     * 加速特效
     */
    updateAccEffect() {
        if (!(this.isFast || this.isSpeed) || !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];
            if (body) {
                node.active = true;
                node.setPosition(body.position);
                node.angle = body.angle;
                node.setScale(this.scale, this.scale);
            } else {
                node.active = false;
            }
        }
    }

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

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

        this.clearPropEffect()

        const len = this.bodyArr.length;
        const energy = Math.min(50, ~~(this.energy / len));
        const foodArr = [];
        for (let i = 0; i < len; i++) {
            const body = this.bodyArr[i];
            body.removeFromParent();
            bodyPool.put(body);

            if (body.position.x > 99999) continue;
            if (i % 2 == 1) continue;

            foodArr.push({
                x: body.position.x + math.randomRange(-10, 10),
                y: body.position.y + math.randomRange(-10, 10),
                energy,
            });
        }

        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));
    }


    clearPropEffect() {
        this.clearMagnet();
        this.clearInvincible();
        this.clearSpeed();
        this.clearDouble();

    }


    /****************************** 磁铁 ******************************/
    useMagnet() {
        this.clearMagnet();
        this.magnetEffectNode.active = true;
        this.magnetEffectNode.getComponent(Animation).play();
        this.eatCollider.radius = Global.PROP_MAGNET_RADIUS;
        this.scheduleOnce(this.clearMagnet, Global.PROP_MAGNET_DUR_TIME)

    }

    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.unschedule(this.clearMagnet)
        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 = value;
    }


    clearInvincible() {
        this.unschedule(this.breakDefense)
        this.unschedule(this.clearInvincible)
        this.defenseEffectNode.active = false
        this.defenseEffectNode.getComponent(Animation).resume()
        this.defenseEffectNode.getComponent(Animation).stop()
        this._invincibleTime = 0;
    }


    useDefense(t = Global.PROP_SHIELD_DUR_TIME) {
        this.clearInvincible();
        this.invincibleTime = t;
        this.defenseEffectNode.active = true;
        this.scheduleOnce(this.breakDefense, this.invincibleTime - Global.PROP_SHIELD_INVINCIBLE_TIME)
    }


    breakDefense() {
        if (this.invincibleTime <= Global.PROP_SHIELD_INVINCIBLE_TIME) return;
        /**3s内继续走无敌 */
        this.clearInvincible()
        this.defenseEffectNode.active = true;
        this.invincibleTime = Global.PROP_SHIELD_INVINCIBLE_TIME;
        this.defenseEffectNode.getComponent(Animation).play();
        this.scheduleOnce(this.clearInvincible, Global.PROP_SHIELD_INVINCIBLE_TIME)
    }


    /***************************** 加速 ***************************/
    /**
     * 使用加速道具
     */
    useSpeed() {
        this.clearSpeed()
        this.moveScale = 2;
        this.isSpeed = true;
        this.scheduleOnce(this.clearSpeed, Global.PROP_SPEED_DUR_TIME)

    }

    clearSpeed() {
        this.unschedule(this.clearSpeed)
        this.isSpeed = false;
        this.moveScale = 1;
    }


    /***************************** 加长 ***************************/
    useGrow() {
        this.fastGrow(Math.floor(Global.PROP_ADD_LENGTH * this.bodyArr.length))
    }


    /***************************** 双倍 ***************************/


    useDouble() {
        this.clearDouble()
        this.doubleStatus = true;
        this.scheduleOnce(this.clearDouble, Global.PROP_DOUBLE_EXP_DUR_TIME)

    }

    clearDouble() {
        this.unschedule(this.clearDouble)
        this.doubleStatus = false;
    }
}