import { autoMineSet, GameConst, tileModel } from 'db://assets/scripts/Config';
import Singleton from "../plugin/Singleton";
import LogMgr from "./LogMgr";
import DataMgr from "./DataMgr";
import GFunc from '../GFunc';
import { random } from 'cc';

export default class tileUtil extends Singleton {
    //根据起点坐标搜索所有的道路地块组
    static searchRoadArr(startX: number, startY: number) {
        let mineInfo = DataMgr.getMineInfo();
        let roadArr: { x: number, y: number }[] = [];
        // 初始化访问标记数组
        const visited = Array.from({ length: mineInfo.tileArr.length },
            () => new Array(mineInfo.tileArr[0].length).fill(false));
        this.searchRoadTile(mineInfo.tileArr, startX, startY, roadArr, visited);
        return roadArr;
    }
    // 递归搜索道路地块
    private static searchRoadTile(
        tileArr: number[][],
        x: number,
        y: number,
        roadArr: { x: number, y: number }[],
        visited: boolean[][]
    ) {
        // 越界检查
        if (x < 0 || y < 0 || x >= tileArr[0].length || y >= tileArr.length) return;
        // 已访问过或非道路地块
        if (visited[y][x] || tileArr[y][x] !== 1) return;

        // 标记为已访问并加入道路数组
        visited[y][x] = true;
        roadArr.push({ x, y });

        // 递归搜索四个方向
        const directions = [
            { dx: 0, dy: -1 }, // 上
            { dx: 0, dy: 1 },  // 下
            { dx: -1, dy: 0 }, // 左
            { dx: 1, dy: 0 }   // 右
        ];

        directions.forEach(({ dx, dy }) => {
            this.searchRoadTile(tileArr, x + dx, y + dy, roadArr, visited);
        });
    }
    //广度搜索：根据起点坐标搜索所有的可挖掘地块组
    static searchDigArr(startX: number, startY: number) {
        let mineInfo = DataMgr.getMineInfo();
        let itemArr: tileModel[] = [];
        let roadArr: { x: number, y: number }[] = this.searchRoadArr(startX, startY);
        // 初始化访问标记数组
        const visited = Array.from({ length: mineInfo.tileArr.length },
            () => new Array(mineInfo.tileArr[0].length).fill(false));
        for (let i = 0; i < roadArr.length; i++) {
            // 递归搜索四个方向
            const directions = [
                { dx: 0, dy: -1 }, // 左上
                { dx: 0, dy: 1 },  // 右下
                { dx: -1, dy: 0 }, // 左下
                { dx: 1, dy: 0 }   // 右上
            ];

            directions.forEach(({ dx, dy }) => {
                //搜索高价值地块
                this.searchItemTile(mineInfo.tileArr, roadArr[i].x + dx, roadArr[i].y + dy, itemArr, visited);
            });
        }
        //LogMgr.log('--搜索后,itemArr:', itemArr);
        return itemArr;
    }
    // 递归搜索可挖掘地块
    private static searchItemTile(
        tileArr: number[][],
        x: number,
        y: number,
        itemArr: tileModel[],
        visited: boolean[][]
    ) {
        // 越界检查
        if (x < 0 || y < 0 || x >= tileArr[0].length || y >= tileArr.length) return;
        if (visited[y][x] || GameConst.goodTileArr.indexOf(tileArr[y][x]) < 0) return;
        // 标记为已访问并加入道路数组
        visited[y][x] = true;
        itemArr.push({ x, y, state: tileArr[y][x] });
        //LogMgr.log('--递归搜索可挖掘地块,itemArr:', itemArr);
    }
    //获取深度优先的下一个可挖的地块
    static getDeepNextPos(pos: { x: number, y: number }) {
        let mineInfo = DataMgr.getMineInfo();
        //如果是最后一行,或者在第一行之前
        if (pos.y >= 49 || pos.y < 0 || !mineInfo.tileArr[pos.y + 1]) {
            return null;
        }
        if (GameConst.mineTileArr.indexOf(mineInfo.tileArr[pos.y + 1][pos.x]) >= 0) {//可挖
            return { x: pos.x, y: pos.y + 1 };
        }
        //下层不可挖，优先选向右挖
        let canRight = GameConst.mineTileArr.indexOf(mineInfo.tileArr[pos.y][pos.x + 1]) >= 0;
        if (!canRight) {
            let canLeft = GameConst.mineTileArr.indexOf(mineInfo.tileArr[pos.y][pos.x - 1]) >= 0;
            if (!canLeft) {
                return null;
            } else {
                return { x: pos.x - 1, y: pos.y };
            }
        } else {
            return { x: pos.x + 1, y: pos.y };
        }
    }
    //检查自身是否可被挖掘-上下左右有一个是道路就能挖
    static checkSelfCanDig(l: number, h: number) {
        if (l < 0 || h < 0 || l >= 50 || h >= 50) return false;
        let tileArr = DataMgr.getMineInfo().tileArr;
        if (!tileArr[h]) { return false; }
        LogMgr.redLog('---checkSelfCanDig:', l, h, tileArr[h][l]);
        if (!tileArr[h][l] || tileArr[h][l] == 1) {//不可挖
            return false;
        }
        let roadArr: { x: number, y: number }[] = [];
        // 递归搜索四个方向
        const directions = [//斜45度方向,矿石在路的哪个方向
            { dh: 0, dl: 1, fx: 'ys' }, // 右上
            { dh: -1, dl: 0, fx: 'zs' },  // 左上 
            { dh: 1, dl: 0, fx: 'yx' }, // 右下
            { dh: 0, dl: -1, fx: 'zx' }   // 左下 
        ]
        for (let i = 0; i < directions.length; i++) {
            let dir = directions[i];
            LogMgr.warn('---dir', dir, h, ',newH:', h + dir.dh, ',tile:', tileArr[h + dir.dh]);
            //LogMgr.log('---state:', tileArr[h + dir.dh][l + dir.dl]);
            if (tileArr[h + dir.dh] && tileArr[h + dir.dh][l + dir.dl] === 1) {
                roadArr.push({ x: l + dir.dl, y: h + dir.dh });
            }
        }
        LogMgr.warn('---roadArr：', roadArr);
        if (roadArr.length > 0) {
            return roadArr;
        } else {
            return false;
        }
    }
    //搜索某种地块的坐标数组
    static searchTileArr(tileType: number) {
        let mineInfo = DataMgr.getMineInfo();
        let itemArr: tileModel[] = [];
        for (let i = 0; i < mineInfo.tileArr.length; i++) {
            if (!mineInfo.tileArr[i]) { continue; }
            for (let j = 0; j < mineInfo.tileArr[i].length; j++) {
                if (mineInfo.tileArr[i][j] === tileType) {
                    itemArr.push({ x: j, y: i, state: tileType });
                }
            }
        }
        return itemArr;
    }
    /** 回溯路径 */
    private static tracePath(parentMap: Map<string, { x: number, y: number, state: number }>, x: number, y: number, state: number): tileModel[] {
        const path: tileModel[] = [];
        let mineInfo = DataMgr.getMineInfo();
        let current = { x, y, state: mineInfo.tileArr[y][x] };

        while (parentMap.has(`${current.x},${current.y}`)) {
            path.unshift({ ...current, state: current.state });
            current = parentMap.get(`${current.x},${current.y}`)!;
            LogMgr.log('---current:', current);
        }
        return path;
    }
    /*根据坐标获取该坐标到附近的道路所需要经过的地块信息（只有可挖掘的地块的信息）
    *@param x 起点x坐标
    *@param y 起点y坐标
    *@return tileModel[] 路径信息数组
    */
    public static searchToRoad(x: number, y: number) {
        let mineInfo = DataMgr.getMineInfo();
        const queue: { x: number, y: number, path: tileModel[], state: number }[] = [];
        const visited = new Map<string, boolean>();
        const parentMap = new Map<string, { x: number, y: number, state: number }>();

        // 初始化队列
        queue.push({ x, y, path: [], state: mineInfo.tileArr[y][x] });
        visited.set(`${x},${y}`, true);

        // 四个方向向量
        const directions = [
            { dx: -1, dy: 0 }, // 左
            { dx: 1, dy: 0 },  // 右
            { dx: 0, dy: -1 }, // 上
            { dx: 0, dy: 1 }   // 下
        ];

        while (queue.length > 0) {
            const current = queue.shift()!;
            //LogMgr.log('当前坐标：', current.x, current.y, ',state:', current.state);
            // 找到道路地块
            if (mineInfo.tileArr[current.y]?.[current.x] === 1) {
                const path = this.tracePath(parentMap, current.x, current.y, current.state);
                //path.length -= 1;
                path.reverse();
                LogMgr.log('已处理，找到路径：', path);
                return path;
            }

            // 遍历四个方向
            for (const dir of directions) {
                const newX = current.x + dir.dx;
                const newY = current.y + dir.dy;
                const key = `${newX},${newY}`;
                // 边界检查
                if (newX < 0 || newY < 0 || newX >= 50 || newY >= 50 || !mineInfo.tileArr[newY]) continue;
                let curState = mineInfo.tileArr[newY][newX];
                //LogMgr.warn('---newX：', newX, '---newY：', newY, !visited.has(key), ',curState:', curState, ',include:', GameConst.mineTileArr.includes(curState));
                // 检查是否可挖掘且未访问过
                if (!visited.has(key)) {
                    if (mineInfo.tileArr[newY][newX] == 1 || GameConst.mineTileArr.includes(curState)) {
                        visited.set(key, true);
                        parentMap.set(key, { x: current.x, y: current.y, state: current.state });
                        //LogMgr.warn('---key：', { x: current.x, y: current.y, state: current.state });
                        queue.push({
                            x: newX,
                            y: newY,
                            path: [...current.path, { x: newX, y: newY, state: curState }],
                            state: curState
                        });
                    }
                }
            }
        }
        return [];
    }
    //当广度搜索穷尽之后，就需要根据地块的序号，分类获取相应的地块数组去挖掘
    public static getTypeTileArr(): { x: number, y: number }[] {
        for (let i = GameConst.goodTileArr.length - 1; i >= 0; i--) {
            let tileArr = GFunc.copyData(this.searchTileArr(GameConst.goodTileArr[i]));
            if (tileArr.length > 0) {
                tileArr.forEach((element: tileModel) => {
                    delete element.state;
                });
                return tileArr;
            }
        }
        return [];
    }
    /**获取普通地块的坐标数组
     */
    public static getNormalTileArr(): { x: number, y: number }[] {
        let normalArr = [2, 3, 4, 5];//普通地砖类型
        for (let i = normalArr.length - 1; i >= 0; i--) {
            let tileArr = GFunc.copyData(this.searchTileArr(normalArr[i]));
            if (tileArr.length > 0) {
                tileArr.forEach((element: tileModel) => {
                    delete element.state;
                });
                return tileArr;
            }
        }
        return [];
    }
    /**获取当前地块周围最近的道路
     * @param h 行
     * @param l 列
     */
    public static getNearRoad(h: number, l: number) {
        let mineInfo = DataMgr.getMineInfo();
        // 四个方向向量
        const directions = [//斜45度方向,矿石在路的哪个方向
            { dh: 0, dl: -1, fx: 'ys' }, // 右上
            { dh: 1, dl: 0, fx: 'zs' },  // 左上 
            { dh: -1, dl: 0, fx: 'ys' }, // 右下
            { dh: 0, dl: 1, fx: 'zx' }   // 左下 
        ]
        for (const dir of directions) {
            const newH = h + dir.dh;
            const newL = l + dir.dl;
            // 边界检查
            if (newH < 0 || newL < 0 || newH >= 50 || newL >= 50 || !mineInfo.tileArr[newH]) { continue; }
            LogMgr.log('+++newH：', newH, '---newL：', newL)
            LogMgr.log('state:', mineInfo.tileArr[newH][newL]);
            if (mineInfo.tileArr[newH][newL] == 1) {
                return { h: newH, l: newL, fx: dir.fx };
            }
        }
        return null;
    }
    /**
     * 搜索最优质的宝箱哇卷路径
     */
    public static searchBoxTilePath() {
        let boxArr: tileModel[] = this.searchTileArr(15);
        let minLength = 99, bestPath: tileModel[] = [], bestBox = null;
        for (let i = 0; i < boxArr.length; i++) {
            let roadArr = this.searchToRoad(boxArr[i].x, boxArr[i].y);
            if (roadArr && roadArr.length < minLength) {
                minLength = roadArr.length;
                bestPath = roadArr;
                bestBox = boxArr[i];
            }
        }
        LogMgr.warn('---bestPath：', GFunc.copyData(bestPath));
        if (bestPath.length == 0) {
            return [];
        }
        bestPath.length -= 1;
        bestPath.reverse();
        bestPath.push(bestBox);
        return bestPath;
    }
    /**
     * 模拟打开新的地块，随机地块类型
     * @param h 
     * @param l 
     */
    public static getResMap(h, l) {
        let mapArr = [];
        let mineInfo = DataMgr.getMineInfo();
        for (let i = h - 2; i <= h + 2; i++) {
            if (i < 0 || i >= 50 || !mineInfo.tileArr[i]) { continue; }
            for (let j = l - 2; j <= l + 2; j++) {
                if (j < 0 || j >= 50 || mineInfo.tileArr[i][j]) { continue; }
                mineInfo.tileArr[i][j] = Math.floor(Math.random() * 18);
                mapArr.push({ x: j, y: i, state: mineInfo.tileArr[i][j] });
            }
        }
        return mapArr;
    }
}