import {
    _decorator,
    math,
    v3,
    Vec3,
    Node,
    Collider2D,
    Contact2DType,
    PhysicsGroup,
    Vec2,
    IVec2Like,
    v2, CircleCollider2D, NodeEventType,
} from "cc";
import { Snake } from "./Snake";
import { DirectionType, EPropType } from "./Common/Enums";
import { Global } from "./Global";
import { MainGame } from "./MainGame";
import { FoodManger } from "./Manager/FoodManger";
import { PropBase } from "./Props/PropBase";
import { Food } from "./Props/Food";

const { ccclass, property } = _decorator;

enum AIState {
    HUNTING,    // 追逐食物
    ESCAPING,   // 逃离危险
    WANDERING,   // 随机游走
}

@ccclass("AISnake")
export class AISnake extends Snake {
    @property({
        range: [1, 5],
        tooltip: "AI难度(1-5)"
    })
    private difficulty: number = 5;
    // private difficulty: number = 1 + Math.random() * 4;

    // AI状态相关
    private currentState: AIState = AIState.WANDERING;
    private targetFood: Vec2 = null;
    private escapeTarget: Snake = null;


    // 计时器
    private behaviorTimer: number = 0;
    private updateTimer = 0;
    private currentUpdateInterval = 0.1;

    // 常量配置
    private readonly BASE_VIEW_DISTANCE = 300;  // 基础视野距离
    private readonly INTERCEPT_DISTANCE = 350;  // 拦截距离
    private readonly ESCAPE_BOUNDARY = 150;  // 逃跑边界
    private readonly SAFE_MARGIN = 3.0;  // 安全边际

    private readonly COLLISION_CHECK_DISTANCE = 500;  // 碰撞检测距离
    private readonly COLLISION_CHECK_DISTANCE_SQ = this.COLLISION_CHECK_DISTANCE * this.COLLISION_CHECK_DISTANCE;

    // 难度参数
    difficultyParams = {
        reactionTime: 0,
        viewDis: 0,
        viewDisSq: 0,
        interceptDis: 0,
        interceptDisSq: 0,
        aggressiveness: 0,
        predictionAccuracy: 0,
        turnSpeed: 0,
    };

    initFlag = false;

    onLoad() {
        super.onLoad();
        const {
            difficulty,
            difficultyParams,
            BASE_VIEW_DISTANCE,
            INTERCEPT_DISTANCE,
        } = this;

        difficultyParams.reactionTime = math.lerp(0.8, 0.15, (difficulty - 1) / 4);

        difficultyParams.viewDis = BASE_VIEW_DISTANCE * (1 + (difficulty - 1) * 0.2);
        difficultyParams.viewDisSq = difficultyParams.viewDis * difficultyParams.viewDis;

        difficultyParams.interceptDis = INTERCEPT_DISTANCE * (1 + (difficulty - 1) * 0.2);
        difficultyParams.interceptDisSq = difficultyParams.interceptDis * difficultyParams.interceptDis;

        difficultyParams.aggressiveness = math.lerp(0.2, 0.7, (difficulty - 1) / 4);
        difficultyParams.predictionAccuracy = math.lerp(0.6, 0.9, (difficulty - 1) / 4);
        difficultyParams.turnSpeed = math.lerp(2, 4.5, (difficulty - 1) / 4);
    }

    setInit() {
        this.initFlag = true;
        this.scheduleOnce(() => {
            this.initFlag = false;
        }, 3);
    }

    onEnable() {
        super.onEnable();

        const eye = this.head.getChildByName("范围").getComponent(CircleCollider2D);
        eye.radius = 100;
        eye.on(Contact2DType.BEGIN_CONTACT, this.onBeginEye, this);
    }

    eatProp(propTs: PropBase) {
        super.eatProp(propTs);
        this.targetFood = null;
        this.setState(AIState.WANDERING, null);
    }

    foodList = [];
    bodyList = [];


    isTurnBack = false;
    onBeginEye(selfCollider: Collider2D, otherCollider: Collider2D) {
        const { group, tag, node } = otherCollider;

        // if (group == PhysicsGroup["Prop"] && tag == EPropType.FOOD) {
        //     this.foodList.push(otherCollider.node);
        // } else if (group == PhysicsGroup["Body"] && otherCollider.tag != this.tag) {
        //     this.bodyList.push(otherCollider.node);
        // }

        if (group === PhysicsGroup["Body"] && tag != this.tag) {

            if (this.isTurnBack) return;
            this.isTurnBack = true;
            this.scheduleOnce(() => {
                // 碰到其他蛇身
                this.head.angle = this.head.angle + 180 + Math.random() * 60 - 30;
                this.setState(AIState.WANDERING, null);
                // this.isFast = true;
                // this.setState(AIState.ESCAPING, node?.parent?.getComponent(Snake));
                this.scheduleOnce(() => {
                    this.isTurnBack = false;
                }, Math.random() * 0.2);
            }, Math.random() * 0.2);
        } else if (group == PhysicsGroup["Wall"]) {
            this.head.angle = this.head.angle + 180 + Math.random() * 60 - 30;
            this.setState(AIState.WANDERING, null);
            this.isFast = true;
        }
    }

    onEndEye(selfCollider: Collider2D, otherCollider: Collider2D) {
        const { group, tag } = otherCollider;

        if (group == PhysicsGroup["Prop"] && tag == EPropType.FOOD) {
            this.foodList.slice(this.foodList.indexOf(otherCollider.node), 1);
        } else if (group == PhysicsGroup["Body"] && otherCollider.tag != this.tag) {
            this.bodyList.slice(this.bodyList.indexOf(otherCollider.node), 1);
        }

        console.log(this.foodList, this.bodyList);
    }

    death() {
        super.death();

        this.node.destroy();

        MainGame.ins.initAiSnake(this.nickName, this.tag);
    }

    // 动态调整AI更新频率
    private updateInterval() {

        const { reactionTime } = this.difficultyParams;

        if (!MainGame.ins.player?.isLife) {
            return reactionTime * 2; // 玩家死亡时降低更新频率
        }

        return reactionTime;

        // const distanceToPlayer = Vec3.distance(
        //     this.head.position,
        //     MainGame.ins.player.head.position
        // );
        //
        // // 距离玩家越近,更新越频繁
        // return math.clamp(
        //     reactionTime + (distanceToPlayer / 1000) * 0.2,
        //     0.05,  // 最小间隔
        //     0.3    // 最大间隔
        // );
    }

    // 分帧更新不同的逻辑
    private updateFrame = 0;
    onUpdate(dt: number) {
        if (!this.isLife) return;

        this.updateTimer += dt;
        this.currentUpdateInterval = this.updateInterval();

        if (this.updateTimer >= this.currentUpdateInterval) {
            this.updateTimer = 0;
            this.updateAIState();
            this.executeCurrentState();
        }

        super.onUpdate(dt);
    }

    private updateAIState() {
        // 只有在非常危险时才逃跑
        if (this.isInDangerousPosition(this.head.position)) {
            this.setState(AIState.ESCAPING, null);
            return;
        }

        // 检查是否有致命威胁需要逃跑
        const threat = this.findNearestThreat();
        if (threat && this.isLethalThreat(threat)) {
            this.setState(AIState.ESCAPING, threat);
            return;
        }

        // 寻找食物
        const nearestFood = this.findNearestFood();
        if (nearestFood) {
            this.setState(AIState.HUNTING, nearestFood);
            return;
        }

        this.setState(AIState.WANDERING, null);
    }

    // 判断是否在极度危险的位置（非常靠近边界）
    private isInDangerousPosition(position: IVec2Like): boolean {
        const dangerBuffer = this.ESCAPE_BOUNDARY;
        const halfWidth = Global.HALF_MAP_WIDTH;
        const halfHeight = Global.HALF_MAP_HEIGHT;

        const distanceToLeft = position.x + halfWidth;
        const distanceToRight = halfWidth - position.x;
        const distanceToBottom = position.y + halfHeight;
        const distanceToTop = halfHeight - position.y;

        return (
            distanceToLeft < dangerBuffer ||
            distanceToRight < dangerBuffer ||
            distanceToBottom < dangerBuffer ||
            distanceToTop < dangerBuffer
        );
    }

    // 判断是否是致命威胁
    private isLethalThreat(threat: Snake): boolean {
        const myPos = this.head.position;
        const threatPos = threat.head.position;
        const disSq = Vec3.squaredDistance(myPos, threatPos);

        return disSq < this.difficultyParams.viewDisSq * 0.5 // 减小威胁判定距离
            && threat.length > this.length * 1.5; // 只有当对方明显比自己强时才逃跑;
    }

    private setState(state: AIState, target: any) {

        this.currentState = state;
        switch (state) {
            case AIState.HUNTING:
                this.targetFood = target as Vec2;
                break;
            case AIState.ESCAPING:
                this.escapeTarget = target as Snake;
                break;
            case AIState.WANDERING:
                this.targetFood = null;
                this.escapeTarget = null;
                break;
        }
    }

    private executeCurrentState() {

        // 执行原有状态逻辑
        switch (this.currentState) {
            case AIState.HUNTING:
                this.executeHunting();
                break;
            case AIState.ESCAPING:
                this.executeEscaping();
                break;
            case AIState.WANDERING:
                this.executeWandering();
                this.setState(AIState.WANDERING, null);
                break;
        }
    }

    private executeHunting() {
        if (!this.targetFood) return;

        const myPos = this.head.position;
        const disSq = Vec2.squaredDistance(myPos as IVec2Like, this.targetFood);
        const targetAngle = this.calculateTargetAngle(this.targetFood);
        // const angleDiff = Math.abs(this.head.angle - targetAngle);

        // 根据角度差决定转向策略
        // if (angleDiff > 90) {
        //     // 大角度差时执行快速转向
        //     this.executeAggressiveTurn(targetAngle);
        //     this.isFast = false;
        // } else {
            // 小角度差时正常追逐
        if (Math.random() < 0.08) {
            this.head.angle = targetAngle;
        } else {
            this.smoothRotateToAngle(targetAngle, this.difficultyParams.turnSpeed);
        }
        // this.isFast = disSq < this.difficultyParams.viewDisSq / 2;
        // }
    }

    // 更激进的转向方法
    private executeAggressiveTurn(targetAngle: number) {
        const currentAngle = this.head.angle;
        let angleDiff = targetAngle - currentAngle;

        angleDiff = this.normalizeAngle(angleDiff);

        // 使用更大的转向速度
        const turnSpeed = this.difficultyParams.turnSpeed * 2.5;
        this.head.angle += math.clamp(angleDiff, -turnSpeed, turnSpeed);
    }

    private normalizeAngle(angle: number): number {
        // 使用位运算代替取模运算
        angle = angle & 359; // 等同于 angle % 360
        return angle > 180 ? angle - 360 : angle;
    }

    private predictFuturePosition(position: IVec2Like, angle: number, distance: number): IVec2Like {
        return Vec2.add(v2(), position, this.getVelocity(angle).multiplyScalar(distance));
    }

    private executeEscaping() {
        if (this.escapeTarget?.head && this.escapeTarget?.isLife) {

            const myPos = this.head.position;
            const threatPos = this.escapeTarget.head.position;
            const disSq = Vec3.squaredDistance(myPos, threatPos);

            // 紧急避让判定
            const isEmergency = disSq < Math.pow(this.radius * 3, 2);
            const escapeAngle = this.calculateAvoidanceAngle(this.escapeTarget);

            if (isEmergency) {
                // 紧急情况：直接设置角度
                this.head.angle = escapeAngle;
                this.isFast = false;
            } else {
                // 非紧急情况：快速但平滑地转向
                const angleDiff = escapeAngle - this.head.angle;
                const normalizedDiff = this.normalizeAngle(angleDiff + 180);
                this.head.angle += math.clamp(normalizedDiff, -15, 15);
                this.isFast = disSq > Math.pow(this.radius * 5, 2);
            }
        } else {
            this.avoidBoundary();
        }
    }

    // 计算避让角度的方法，增加紧急情况下的处理
    private calculateAvoidanceAngle(threat: Snake): number {
        const threatPos = threat.head.position;
        const baseEscapeAngle = this.calculateEscapeAngle(threatPos);

        // 检查基础逃生角度是否安全
        if (!this.willHitBoundary(baseEscapeAngle)) {
            return baseEscapeAngle;
        }

        // 如果基础角度不安全，寻找最佳替代角度
        const angles = [
            baseEscapeAngle,
            baseEscapeAngle + 45, baseEscapeAngle - 45,
            baseEscapeAngle + 90, baseEscapeAngle - 90,
            baseEscapeAngle + 135, baseEscapeAngle - 135,
            baseEscapeAngle + 180
        ];

        let bestAngle = baseEscapeAngle;
        let maxSafety = -Infinity;

        for (const angle of angles) {
            if (this.willHitBoundary(angle)) continue;

            const safety = this.evaluateEscapeAngleSafety(angle, threat);
            if (safety > maxSafety) {
                maxSafety = safety;
                bestAngle = angle;
            }
        }

        return bestAngle;
    }

    // 评估逃生角度的安全性
    private evaluateEscapeAngleSafety(angle: number, threat: Snake): number {
        const myPos = this.head.position;
        const futurePos = this.predictFuturePosition(myPos, angle, this.radius * 4);
        let safety = 100;

        // 检查与威胁的距离
        const threatDisSq = Vec2.squaredDistance(futurePos as IVec2Like, threat.head.position);
        safety += threatDisSq;

        // 检查边界距离
        const boundaryDist = this.getDistanceToBoundary(futurePos);
        safety += boundaryDist * 2;

        // 检查与其他蛇的距离
        const allSnakes = [...MainGame.ins.animalNode.children, MainGame.ins.player.node]
            .map(node => node.getComponent(Snake))
            .filter(snake => snake && snake !== this && snake !== threat && snake.isLife);

        for (const snake of allSnakes) {
            const disSq = Vec2.squaredDistance(futurePos, snake.head.position as IVec2Like);
            if (disSq < this.COLLISION_CHECK_DISTANCE_SQ) {
                safety -= (this.COLLISION_CHECK_DISTANCE_SQ - disSq);
            }
        }

        return safety;
    }

    private willHitBoundary(angle: number): boolean {
        const myPos = this.head.position;
        const futurePos = this.predictFuturePosition(myPos, angle, this.radius * 4);
        const boundaryDist = this.getDistanceToBoundary(futurePos);
        return boundaryDist < this.ESCAPE_BOUNDARY;
    }

    // 获取到边界的距离
    private getDistanceToBoundary(position: IVec2Like): number {
        return Math.min(
            Global.HALF_MAP_WIDTH - Math.abs(position.x),
            Global.HALF_MAP_HEIGHT - Math.abs(position.y)
        );
    }

    private executeWandering() {
        // 增加方向改变的概率
        if (math.randomRangeInt(0, 30) == 0) {
            const direction = math.randomRangeInt(0, 3);
            const speed = math.randomRangeInt(1, 3);

            if (direction === DirectionType.LEFT) {
                this.head.angle += speed;
            } else if (direction === DirectionType.RIGHT) {
                this.head.angle -= speed;
            }
        }

        // 减少速度变化的频率
        this.isFast = math.random() < this.difficultyParams.aggressiveness * 0.05;
    }

    private avoidBoundary() {
        const myPos = this.head.position;
        const { HALF_MAP_WIDTH, HALF_MAP_HEIGHT } = Global;
        const boundaryBuffer = this.ESCAPE_BOUNDARY;

        const isNearLeft = myPos.x < -HALF_MAP_WIDTH + boundaryBuffer;
        const isNearRight = myPos.x > HALF_MAP_WIDTH - boundaryBuffer;
        const isNearBottom = myPos.y < -HALF_MAP_HEIGHT + boundaryBuffer;
        const isNearTop = myPos.y > HALF_MAP_HEIGHT - boundaryBuffer;

        let targetAngle = this.head.angle;
        let isCorner = false;

        if (isNearLeft && isNearBottom) {
            targetAngle = 45; // 右上
            isCorner = true;
        } else if (isNearRight && isNearBottom) {
            targetAngle = 135; // 左上
            isCorner = true;
        } else if (isNearLeft && isNearTop) {
            targetAngle = 315; // 右下
            isCorner = true;
        } else if (isNearRight && isNearTop) {
            targetAngle = 225; // 左下
            isCorner = true;
        } else {
            if (isNearLeft) targetAngle = 0; // 向右
            else if (isNearRight) targetAngle = 180; // 向左

            if (isNearBottom) targetAngle = 90; // 向上
            else if (isNearTop) targetAngle = 270; // 向下
        }

        const turnSpeed = isCorner ? this.difficultyParams.turnSpeed * 1.5 : this.difficultyParams.turnSpeed;
        this.smoothRotateToAngle(targetAngle, turnSpeed);
    }

    private findNearestFood(): Vec2 | null {
        const myPos = this.head.position;
        let nearestFood = null;
        let { viewDisSq, predictionAccuracy, } = this.difficultyParams;

        let minDisSq = viewDisSq;

        const foods = FoodManger.ins.node.children;
        // const boundaryBuffer = this.ESCAPE_BOUNDARY;
        const randomFactor = math.lerp(0.7, 1, predictionAccuracy);

        // const { HALF_MAP_WIDTH, HALF_MAP_HEIGHT } = Global;

        const candidateFoods = foods.filter(food => {
            if (!food.isValid || !food.active || !food["canEaten"]) return false;

            const foodPos = food.position;
            // 使用曼哈顿距离进行快速预筛选
            return Math.abs(foodPos.x - this.head.position.x) + Math.abs(foodPos.y - this.head.position.y)
                < this.difficultyParams.viewDis * 1.5;
        });

        for (const food of candidateFoods) {
            const foodPos = food.position;
            const disSq = Vec3.squaredDistance(myPos, foodPos);

            // 检查食物是否靠近墙体
            // if (foodPos.x < -HALF_MAP_WIDTH + boundaryBuffer || foodPos.x > HALF_MAP_WIDTH - boundaryBuffer ||
            //     foodPos.y < -HALF_MAP_HEIGHT + boundaryBuffer || foodPos.y > HALF_MAP_HEIGHT - boundaryBuffer) {
            //     continue; // 跳过靠近墙体的食物
            // }

            if (disSq < minDisSq) {
                if (math.random() < randomFactor) {
                    minDisSq = disSq;
                    nearestFood = foodPos;
                }
            }
        }

        if (nearestFood && predictionAccuracy > 0.7) {
            const competitors = this.findCompetitorsForFood(nearestFood, minDisSq);
            if (competitors.length > 0 && !this.canReachFoodFirst(nearestFood, minDisSq, competitors)) {
                return this.findAlternativeFood(foods, myPos, competitors);
            }
        }

        return nearestFood;
    }

    // 寻找替代食物
    private findAlternativeFood(foods: Node[], myPos: Vec3, competitors: Snake[]): Vec2 | null {
        let bestAlternative = null;
        let bestScore = -1;

        const { viewDisSq } = this.difficultyParams;

        for (const food of foods) {
            if (!food.isValid || !food.active) continue;

            const foodPos = food.position;
            const disSq = Vec3.squaredDistance(myPos, foodPos);

            if (disSq > viewDisSq) continue;

            // 计算这个食物的得分（考虑距离和竞争者）
            const score = this.calculateFoodScore(foodPos, disSq, competitors);

            if (score > bestScore) {
                bestScore = score;
                bestAlternative = foodPos;
            }
        }

        return bestAlternative;
    }

    // 计算食物的得分
    private calculateFoodScore(foodPos: Vec3, disSq: number, competitors: Snake[]): number {
        const params = this.difficultyParams;

        // 基础分数（距离越近分数越高）
        let score = 1 - (disSq / params.viewDis);

        // 根据竞争者调整分数
        for (const competitor of competitors) {
            const competitorDisSq = Vec3.squaredDistance(competitor.head.position, foodPos);
            if (competitorDisSq < disSq) {
                // 如果竞争者更近，降低分数
                score *= 0.5;
            }
        }

        // 根据难度添加一些随机性
        score *= math.lerp(0.8, 1.2, math.random() * params.predictionAccuracy);

        return score;
    }

    // 判断是否能在竞争者之前到达食物
    private canReachFoodFirst(foodPos: Vec3, myDisSq: number, competitors: Snake[]): boolean {
        const mySpeed = this.speed * this.moveScale;
        const myTimeToReach = myDisSq / mySpeed;

        for (const competitor of competitors) {
            const competitorPos = competitor.head.position;
            const competitorDisSq = Vec3.squaredDistance(competitorPos, foodPos);
            const competitorSpeed = competitor.speed * (competitor instanceof AISnake ? 2 : 1);
            const competitorTimeToReach = competitorDisSq / competitorSpeed;

            if (competitorTimeToReach < myTimeToReach) {
                return false;
            }
        }

        return true;
    }

    // 寻找同样在追逐食物的竞争者
    private findCompetitorsForFood(foodPos: Vec3, minDisSq: number): Snake[] {
        const competitors: Snake[] = [];
        const allSnakes = [...MainGame.ins.animalNode.children, MainGame.ins.player.node];

        for (const snakeNode of allSnakes) {
            const snake = snakeNode.getComponent(Snake);
            if (snake === this || !snake.isLife) continue;

            const distance = Vec3.squaredDistance(snake.head.position, foodPos);
            // 只考虑距离相近或更近的竞争者
            if (distance <= minDisSq * 1.2) {
                competitors.push(snake);
            }
        }

        return competitors;
    }

    private findNearestThreat(): Snake | null {
        const myPos = this.head.position;
        let nearestThreat = null;

        const allSnakes = [...MainGame.ins.animalNode.children, MainGame.ins.player.node];

        for (const snakeNode of allSnakes) {
            const snake = snakeNode.getComponent(Snake);
            if (snake === this) continue;

            // 检查身体威胁，使用实际的身体半径
            for (let i = 0; i < snake.bodyArr.length; i++) {
                const bodyPart = snake.bodyArr[i];
                const bodyDisSq = Vec3.squaredDistance(myPos, bodyPart.position);

                const threatDisSq = Math.pow(this.radius * this.SAFE_MARGIN, 2);

                if (bodyDisSq < threatDisSq) {
                    nearestThreat = snake;
                    break;
                }
            }
        }

        return nearestThreat;
    }

    private calculateEscapeAngle(threatPos: IVec2Like): number {
        const myPos = this.head.position;
        return math.toDegree(Math.atan2(
            myPos.y - threatPos.y,
            myPos.x - threatPos.x
        ));
    }

    private calculateTargetAngle(targetPos: IVec2Like): number {
        const myPos = this.head.position;
        return math.toDegree(Math.atan2(
            targetPos.y - myPos.y,
            targetPos.x - myPos.x
        ));
    }

    private smoothRotateToAngle(targetAngle: number, turnSpeed: number) {
        const currentAngle = this.head.angle;
        let angleDiff = targetAngle - currentAngle;

        angleDiff = this.normalizeAngle(angleDiff);

        // 根据角度差的大小调整转向速度
        this.head.angle += math.clamp(angleDiff, -turnSpeed, turnSpeed);
    }

    setDifficulty(level: number) {
        this.difficulty = math.clamp(level, 1, 5);
    }
}