import {
    _decorator, Color, Component, Graphics, Layers, Node, UITransform, Vec3, view,
} from 'cc';
import { CELL_PIXEL, CAMERA_ORTHO_HALF, DESIGN_HEIGHT } from '../core/GridConstants';
import { cellToWorldCenter, getHalfCellSize } from '../core/GridCoords';
import { EventManager, EventType } from '../core/EventManager';
import { GameManager } from '../manager/GameManager';
import { GridSnapHelper } from '../level/GridSnapHelper';

const { ccclass } = _decorator;

const UI_LAYER = Layers.Enum.UI_2D;

/** 对齐 Unity LineGridRenderer：导航按钮切换的满屏等距辅助网格 */
@ccclass('LineGridRenderer')
export class LineGridRenderer extends Component {
    static instance: LineGridRenderer | null = null;

    /** 以中心向外的格子半径（菱形个数 ≈ (2r+1)²） */
    radius = 24;
    cellSize = CELL_PIXEL;

    private graphics: Graphics | null = null;
    private visible = false;

    static ensure(parent: Node): LineGridRenderer {
        LineGridRenderer.purgeDuplicates(parent);

        let comp = LineGridRenderer.instance?.isValid ? LineGridRenderer.instance : null;
        if (!comp) {
            const found = LineGridRenderer.findUnder(parent);
            comp = found?.getComponent(LineGridRenderer) ?? null;
        }
        if (!comp) {
            const node = new Node('LineGrid');
            node.parent = parent;
            comp = node.addComponent(LineGridRenderer);
        } else if (comp.node.parent !== parent) {
            comp.node.parent = parent;
        }

        comp.setupRuntime();
        comp.sendToBack();
        return comp;
    }

    /** 移除误挂在关卡内的重复 LineGrid（会导致叠线无法关闭） */
    private static purgeDuplicates(entrance: Node) {
        const keep = LineGridRenderer.instance?.isValid
            ? LineGridRenderer.instance.node
            : LineGridRenderer.findUnder(entrance);
        const walk = (node: Node) => {
            for (let i = node.children.length - 1; i >= 0; i--) {
                const ch = node.children[i];
                if (ch.name === 'LineGrid' && ch !== keep) {
                    ch.destroy();
                    continue;
                }
                walk(ch);
            }
        };
        walk(entrance);
    }

    private static findUnder(root: Node): Node | null {
        if (root.name === 'LineGrid') return root;
        for (const ch of root.children) {
            const hit = LineGridRenderer.findUnder(ch);
            if (hit) return hit;
        }
        return null;
    }

    onLoad() {
        if (LineGridRenderer.instance && LineGridRenderer.instance !== this) {
            this.node.destroy();
            return;
        }
        LineGridRenderer.instance = this;
        this.setupRuntime();
        EventManager.register(EventType.LevelInit, this.onLevelInit);
    }

    onDestroy() {
        EventManager.remove(EventType.LevelInit, this.onLevelInit);
        if (LineGridRenderer.instance === this) LineGridRenderer.instance = null;
    }

    isGridVisible(): boolean {
        return this.visible;
    }

    private setupRuntime() {
        this.node.layer = UI_LAYER;
        if (!this.node.getComponent(UITransform)) {
            this.node.addComponent(UITransform).setContentSize(1, 1);
        }
        const g = this.getComponent(Graphics) ?? this.addComponent(Graphics);
        this.graphics = g;
        g.lineWidth = 1.4;
        g.strokeColor = new Color(0, 0, 0, 255);
        if (!this.visible) {
            g.clear();
            this.node.active = false;
        }
    }

    private onLevelInit = () => {
        this.purgeEditorGrid();
        this.syncLevelOffset();
        this.updateGridRadius();
        if (this.visible) {
            this.rebuild();
            this.node.active = true;
            this.sendToBack();
        } else {
            this.graphics?.clear();
            this.node.active = false;
        }
    };

    toggleGridVisibility() {
        this.setupRuntime();
        this.visible = !this.visible;
        if (this.visible) {
            this.purgeEditorGrid();
            this.syncLevelOffset();
            this.updateGridRadius();
            this.rebuild();
            this.node.active = true;
            this.sendToBack();
        } else {
            this.graphics?.clear();
            this.node.active = false;
        }
    }

    /** 移除编辑器 GridSnapHelper 遗留的蓝色/灰色参考格 */
    private purgeEditorGrid() {
        const entrance = this.node.parent;
        if (entrance?.isValid) {
            GridSnapHelper.purgeRuntimeGrids(entrance);
        }
        const scene = this.node.scene;
        if (scene?.isValid) {
            GridSnapHelper.purgeRuntimeGrids(scene);
        }
    }

    /** 保持在 MainLevelEntrance 最底层，不遮挡关卡内砖块/角色 */
    private sendToBack() {
        const parent = this.node.parent;
        if (parent?.isValid) {
            this.node.setSiblingIndex(0);
        }
    }

    /** 与关卡根节点对齐，网格覆盖当前可见砖块区域 */
    private syncLevelOffset() {
        const parent = this.node.parent;
        if (!parent) return;
        const levelRoot = parent.children.find(
            (c) => c?.isValid && c !== this.node && (c.name ?? '').startsWith('Level'),
        );
        if (levelRoot?.isValid) {
            const p = levelRoot.position;
            this.node.setPosition(p.x, p.y, 0);
        } else {
            this.node.setPosition(0, 0, 0);
        }
    }

    private updateGridRadius() {
        const b = GameManager.instance?.getCurLevel()?.boundary;
        const vs = view.getVisibleSize();
        const halfH = CAMERA_ORTHO_HALF;
        const halfW = halfH * (vs.width / Math.max(vs.height, DESIGN_HEIGHT));
        const cover = Math.ceil(Math.max(halfW, halfH) / (CELL_PIXEL * 0.35)) + 6;

        if (b) {
            this.radius = Math.max(cover, b.x + 8, b.y + 8);
        } else {
            this.radius = cover;
        }
    }

    private rebuild() {
        const g = this.graphics;
        if (!g) return;
        g.clear();

        const { halfW, halfH } = getHalfCellSize();
        const r = this.radius;
        for (let x = -r; x <= r; x++) {
            for (let y = -r; y <= r; y++) {
                const c = cellToWorldCenter(new Vec3(x, y, 0));
                g.moveTo(c.x, c.y + halfH);
                g.lineTo(c.x + halfW, c.y);
                g.lineTo(c.x, c.y - halfH);
                g.lineTo(c.x - halfW, c.y);
                g.close();
            }
        }
        g.stroke();
    }
}
