'use strict';

/** AppRoot Inspector：SwitchLevel + 游戏调试（对齐 Unity TestPlayer） */

function compUuid(dump) {
    if (!dump || !dump.value) return '';
    const u = dump.value.uuid;
    return (u && u.value) ? u.value : (typeof u === 'string' ? u : '');
}

function nodeUuid(dump) {
    if (!dump || !dump.value) return '';
    const n = dump.value.node;
    return (n && n.value && n.value.uuid) ? n.value.uuid : '';
}

function getMessageProtocolScene(el) {
    let element = el;
    while (element) {
        const root = element.getRootNode && element.getRootNode();
        element = element.parentElement || (root && root.host) || null;
        if (element && element.messageProtocol && element.messageProtocol.scene) {
            return element.messageProtocol.scene;
        }
    }
    return 'scene';
}

async function callMethod(contextEl, uuid, name, args) {
    if (!uuid || typeof Editor === 'undefined') return;
    const protocols = [];
    const primary = getMessageProtocolScene(contextEl);
    if (primary) protocols.push(primary);
    if (protocols.indexOf('scene') < 0) protocols.push('scene');
    let lastErr;
    for (let i = 0; i < protocols.length; i++) {
        try {
            await Editor.Message.request(protocols[i], 'execute-component-method', {
                uuid,
                name,
                args: args || [],
            });
            return;
        } catch (e) {
            lastErr = e;
        }
    }
    console.warn('[game-controller-inspector]', name, lastErr);
}

async function findGameControllerUuid(nu) {
    if (!nu) return null;
    try {
        const node = await Editor.Message.request('scene', 'query-node', nu);
        for (const c of node?.__comps__ || []) {
            if (c.type === 'GameController' || c.type === '8940aPSKJhGKKIBE/qKnFm7') {
                return c.value.uuid.value;
            }
        }
    } catch (e) {
        console.warn('[game-controller-inspector] query-node failed', e);
    }
    return null;
}

async function callGame(contextEl, dump, method, args) {
    const gc = await findGameControllerUuid(nodeUuid(dump));
    if (!gc) {
        console.warn('[game-controller-inspector] 请先点预览 ▶，等关卡加载后再调试');
        return;
    }
    await callMethod(contextEl, gc, method, args);
}

function parseStep(raw) {
    const n = parseInt(String(raw || '1'), 10);
    return Number.isNaN(n) || n === 0 ? 1 : n;
}

let lastDebugAt = 0;
function guardDebug(fn) {
    return () => {
        const now = Date.now();
        if (now - lastDebugAt < 350) return;
        lastDebugAt = now;
        fn();
    };
}

module.exports = Editor.Panel.define({
    template: `
        <div class="gc-footer">
            <ui-label class="hint">① 预览 ▶  ② GameController 填 inputLevel  ③ 点 SwitchLevel</ui-label>
            <div class="row level-nav">
                <ui-button class="btn-prev">上一关</ui-button>
                <ui-button class="btn-next">下一关</ui-button>
            </div>
            <ui-button class="btn-switch blue">SwitchLevel</ui-button>
            <ui-label class="sep">— 游戏调试（须预览运行中）—</ui-label>
            <div class="row">
                <ui-label class="lbl">步数</ui-label>
                <ui-input class="step" value="1"></ui-input>
            </div>
            <div class="row">
                <ui-button class="fwd">前进</ui-button>
                <ui-button class="back">后退</ui-button>
                <ui-button class="jump">跳</ui-button>
            </div>
            <div class="row">
                <ui-button class="rot-l">左转</ui-button>
                <ui-button class="rot-r">右转</ui-button>
                <ui-button class="info">坐标</ui-button>
            </div>
            <div class="row">
                <ui-button class="end">结束输入</ui-button>
                <ui-button class="veh">载具+1</ui-button>
                <ui-button class="reset">重置关卡</ui-button>
            </div>
        </div>
    `,
    style: `
        .gc-footer { margin-top: 6px; }
        .gc-footer .hint, .gc-footer .sep {
            opacity: 0.8;
            font-size: 11px;
            margin: 6px 0;
            display: block;
        }
        .gc-footer .row { display: flex; gap: 4px; margin-bottom: 6px; }
        .gc-footer .lbl { font-size: 11px; align-self: center; min-width: 28px; }
        .gc-footer .step { flex: 1; }
        .gc-footer ui-button { flex: 1; }
        .gc-footer .level-nav { margin-bottom: 4px; }
        .gc-footer .btn-switch { width: 100%; margin-bottom: 4px; }
    `,
    $: {
        hint: '.hint',
        step: '.step',
        btnSwitch: '.btn-switch',
        btnPrev: '.btn-prev',
        btnNext: '.btn-next',
        fwd: '.fwd',
        back: '.back',
        jump: '.jump',
        rotL: '.rot-l',
        rotR: '.rot-r',
        info: '.info',
        end: '.end',
        veh: '.veh',
        reset: '.reset',
    },
    ready() {
        const ctx = () => this.$this || this.$.btnSwitch;
        const step = () => parseStep(this.$.step.value);
        this.$.btnPrev.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'prevLevel', [])));
        this.$.btnNext.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'nextLevel', [])));
        this.$.btnSwitch.addEventListener('confirm', () => {
            void callMethod(ctx(), compUuid(this.dump), 'switchLevelFromBootstrap', []);
        });
        this.$.fwd.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugMove', [step()])));
        this.$.back.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugMove', [-step()])));
        this.$.jump.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugJump', [])));
        this.$.rotL.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugRotateLeft', [1])));
        this.$.rotR.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugRotateRight', [1])));
        this.$.info.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugPlayerInfo', [])));
        this.$.end.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugInputEnd', [])));
        this.$.veh.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugVehicleMove', [1])));
        this.$.reset.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugResetLevel', [])));
    },
    update(dump) {
        if (dump) this.dump = dump;
    },
});
