import { existsSync } from "fs";
import { needleLog } from "./logging.js";

const root = process.cwd();

const editorSyncPackageName = "@needle-tools/editor-sync"


/** sent from the editor when the server was already running 
/* when the user added the editor sync component
/* at the top of this file we check if the component is present in the scene
/* and enabled and if it's not it will not install the editor plugin
*/
let editorSyncEnabled = false;

/**
 * @param {"build" | "serve"} command
 * @param {import('../types/needleConfig').needleMeta | null | undefined} config
 * @param {import('../types').userSettings} userSettings
 * @param {import('vite').Plugin[]} [pluginsArray]
 * @returns {Promise<import('vite').Plugin | undefined>}
 */
export async function editorConnection(command, config, userSettings, pluginsArray) {
    if (command === "build") return;

    // Editor sync currently only supports Unity
    if (typeof config.generator === "string" && !config.generator.includes("Unity")) return;

    if (!config) {
        setTimeout(() => needleLog("needle-editor-sync", "Needle Editor Sync can not be installed automatically to vite: missing config", "warn"), 1000);
        return createPlugin(false);
    }

    if (config?.dontInstallEditor === true || userSettings?.dontInstallEditor === true) return;

    const needleEditorSettings = config.needleEditor;
    // If the component was added while the server was already running
    // if (editorSyncEnabled === false) {
    //     if (!needleEditorSettings) {
    //         setTimeout(() => console.log("Needle Editor Sync is not enabled. Add a 'Needle Editor Sync' component to your scene to enable (no component)"), 1000);
    //         return createPlugin(false);
    //     }
    // }
    if (needleEditorSettings && needleEditorSettings.enabled === false) {
        setTimeout(() => needleLog("needle-editor-sync", "Needle Editor Sync is not enabled. Add a 'Needle Editor Sync' component to your scene to enable", "warn"), 1000);
        return createPlugin(false);
    }

    // Check if the editor package is installed
    let path = root + `/node_modules/${editorSyncPackageName}/plugins/index.js`;
    if (existsSync(path) === false) {
        setTimeout(() => needleLog("needle-editor-sync", `${editorSyncPackageName} is not installed: Add the "Needle Editor Sync" component to your scene if you want to send changes directly from the Unity Editor to web app`, "warn"), 1000);
        return createPlugin(false);
    }


    // Load vite plugin
    if (!path.startsWith("file:")) path = "file:" + path;
    const { needleEditor } = /** @type {{ needleEditor: () => Record<string, unknown> }} */ (await import(path));
    setTimeout(() => needleLog("needle-editor-sync", "Automatically installed Needle Editor Sync"), 500)
    const method = needleEditor();
    const typedPluginsArray = /** @type {Array<Record<string, unknown>>} */ (pluginsArray);
    typedPluginsArray.push(method);
    return createPlugin(true);
}

/** @param {boolean} isInstalled */
function createPlugin(isInstalled) {
    return /** @type {import('vite').Plugin} */ ({
        name: "needle-editor-connection",
        // Setup HMR port for connecting to the editor
        config(config) {
            if (isInstalled) {
                if (!config.server) config.server = {};
                if (!config.server.hmr) config.server.hmr = {};
                if (config.server.hmr === false) {
                    setTimeout(() => needleLog("needle-editor-sync", "HMR is disabled, not initializing Needle Editor", "warn"));
                    return;
                }
                if (config.server.hmr.port === undefined) {
                    config.server.hmr.port = 1107;
                    setTimeout(() => needleLog("needle-editor-sync", "Update HMR port to " + config.server.hmr.port));
                }
            }

        },

        configureServer(server) {
            try 
            {
                server.ws.on('connection', (socket, _request) => {
    
                    // console.log("Send editor sync status: " + isInstalled);
                    const reply = {
                        type: "needle:editor-sync:installation-status",
                        data: isInstalled
                    }
                    socket.send(JSON.stringify(reply));
    
                    socket.on('message', async (bytes) => {
                        if (bytes?.length < 50) {
                            const message = Buffer.from(bytes).toString();
                            if (message === "needle:editor:restart") {
                                needleLog("needle-editor-sync", "Received request for a soft restart of the vite server...")
                                // This just restarts the vite server
                                server.restart();
                            }
                            else if (message === "needle:editor:stop") {
                                process.exit();
                            }
                            else if (message === `{"type":"ping"}`) {
                                socket.send(JSON.stringify({ type: "pong" }));
                            }
                            else if (message === "needle:editor:editor-sync-enabled") {
                                needleLog("needle-editor-sync", "Editor sync enabled")
                                editorSyncEnabled = true;
                            }
                            else if (message === "needle:editor:editor-sync-disabled") {
                                editorSyncEnabled = false;
                            }
                        }
                    })
                });
            }
            catch(/** @type {unknown} */ err){
                needleLog("needle-editor-sync", "Error in needle-editor-connection", "error")
                console.error(err)
            }
        }
    })
}