'use strict';

const fs = require('fs');
const path = require('path');
const prefabSync = require('./prefab-sync');
const bakeIgnore = require('./bake-ignore');

const IMPORT_DEBOUNCE_MS = 900;

/** levelId → debounce timer */
const importTimers = new Map();
let prefabWatcher = null;
let broadcastUnsubs = [];

function addBroadcastListener(message, handler) {
    const fn = Editor.Message.__protected__?.addBroadcastListener || Editor.Message.addBroadcastListener;
    if (typeof fn !== 'function') {
        console.warn(`[level-map-editor] addBroadcastListener unavailable for ${message}`);
        return null;
    }
    fn.call(Editor.Message, message, handler);
    return () => {
        const rm = Editor.Message.__protected__?.removeBroadcastListener || Editor.Message.removeBroadcastListener;
        if (typeof rm === 'function') rm.call(Editor.Message, message, handler);
    };
}

function scheduleImportFromPrefab(levelId, source) {
    if (!levelId || bakeIgnore.shouldIgnoreImport(levelId)) return;
    if (importTimers.has(levelId)) clearTimeout(importTimers.get(levelId));
    importTimers.set(
        levelId,
        setTimeout(() => {
            importTimers.delete(levelId);
            runImportFromPrefab(levelId, source);
        }, IMPORT_DEBOUNCE_MS),
    );
}

function runImportFromPrefab(levelId, source) {
    if (bakeIgnore.shouldIgnoreImport(levelId)) return null;
    try {
        const result = prefabSync.importLevelFromPrefab(levelId);
        if (!result.ok) {
            console.warn(`[level-map-editor] prefab import skipped Level${levelId}: ${result.reason}`);
            return result;
        }
        console.log(
            `[level-map-editor] prefab → JSON Level${levelId} (ground ${result.ground}, border ${result.border}, theme ${result.theme || '-'}) [${source}]`,
        );
        void prefabSync.refreshDatabaseAsset();
        Editor.Message.broadcast('level-map-editor:prefab-synced', {
            levelId,
            source,
            ground: result.ground,
            border: result.border,
            theme: result.theme,
        });
        return result;
    } catch (e) {
        console.error(`[level-map-editor] prefab import failed Level${levelId}`, e);
        return { ok: false, reason: e.message, levelId };
    }
}

async function handleAssetDbEvent(...args) {
    let url = '';
    for (const arg of args) {
        if (typeof arg === 'string') {
            if (arg.includes('level-prefabs/Level') && arg.endsWith('.prefab')) url = arg;
            else if (arg.startsWith('db://') && arg.includes('Level') && arg.endsWith('.prefab')) url = arg;
        } else if (arg && typeof arg === 'object') {
            if (typeof arg.url === 'string') url = arg.url;
            else if (typeof arg.path === 'string') url = arg.path;
        }
    }
    if (!url && typeof args[0] === 'string' && !args[0].includes('/')) {
        try {
            url = await Editor.Message.request('asset-db', 'query-url', args[0]);
        } catch {
            /* ignore */
        }
    }
    const levelId = prefabSync.extractLevelIdFromUrl(url);
    if (levelId) scheduleImportFromPrefab(levelId, 'asset-db');
}

function watchPrefabDirectory() {
    const dir = path.join(Editor.Project.path, prefabSync.PREFAB_DIR_REL);
    if (!fs.existsSync(dir)) return;
    try {
        prefabWatcher = fs.watch(dir, (_event, filename) => {
            const levelId = prefabSync.extractLevelIdFromFilename(filename);
            if (levelId) scheduleImportFromPrefab(levelId, 'fs-watch');
        });
    } catch (e) {
        console.warn('[level-map-editor] prefab fs.watch failed', e);
    }
}

function registerAssetListeners() {
    const events = [
        'asset-db:asset-change',
        'asset-db:asset-changed',
        'asset-db:assets-changed',
        'asset-db:asset-add',
        'asset-db:assets-created',
    ];
    for (const message of events) {
        const unsub = addBroadcastListener(message, (...args) => {
            void handleAssetDbEvent(...args);
        });
        if (unsub) broadcastUnsubs.push(unsub);
    }
}

exports.methods = {
    openPanel() {
        const id = 'level-map-editor';
        try {
            Editor.Panel.open(id);
            console.log(`[${id}] Panel.open('${id}')`);
        } catch (e) {
            console.error(`[${id}] open failed:`, e);
        }
    },

    markBakePending(levelId, durationMs) {
        bakeIgnore.markBakePending(levelId, durationMs);
    },

    importLevelFromPrefab(levelId) {
        return runImportFromPrefab(Number(levelId), 'manual');
    },
};

exports.load = function () {
    prefabSync.clearSpriteUuidCache();
    registerAssetListeners();
    watchPrefabDirectory();
    console.log('[level-map-editor] extension loaded (v1.7.1, prefab→JSON sync enabled)');
};

exports.unload = function () {
    for (const unsub of broadcastUnsubs) {
        try {
            unsub();
        } catch {
            /* ignore */
        }
    }
    broadcastUnsubs = [];
    if (prefabWatcher) {
        try {
            prefabWatcher.close();
        } catch {
            /* ignore */
        }
        prefabWatcher = null;
    }
    for (const timer of importTimers.values()) clearTimeout(timer);
    importTimers.clear();
    console.log('[level-map-editor] extension unloaded');
};
