import { access, existsSync, readFile, readFileSync } from "fs";
import { readdir, stat } from "fs/promises";

let pluginsConfig: any = {};
let pluginsi18n: any = {};
let changedPlugins: string | any[] = [];
/**
 * @en Registration method for the main process of Extension
 * @zh 为扩展的主进程的注册方法
 */
export const methods: { [key: string]: (...any: any) => any } = {
    /**
     * @en A method that can be triggered by message
     * @zh 通过 message 触发的方法
     */
    showLog() {
        console.log('Hello World');
    },
    async refreshPlugins() {
        await getPluginsConfig();
        changedPlugins = getChangedPlugins();
        // console.log('refresh: ', changedPlugins);
        if (changedPlugins.length) {
            for (let i = 0; i < changedPlugins.length; i++) {
                const plugin = changedPlugins[i];
                if (plugin.name == "plugin-bridge") {
                    continue;
                }
                console.log("disable plugin: ", plugin.path);
                Editor.Package.disable(plugin.path);
            }
        }
    },
    onPluginDisable(params) {
        for (let i = 0; i < changedPlugins.length; i++) {
            const plugin = changedPlugins[i];
            if (plugin.name == "plugin-bridge") {
                continue;
            }
            console.log("enable plugin: ", plugin.path);
            Editor.Package.enable(plugin.path);
        }
        changedPlugins = [];
        getPluginsi18n();
    },
};

/**
 * @en Method Triggered on Extension Startup
 * @zh 扩展启动时触发的方法
 */
export async function load() {
    await getPluginsConfig();
    await getPluginsi18n();
}

/**
 * @en Method triggered when uninstalling the extension
 * @zh 卸载扩展时触发的方法
 */
export function unload() { }

function getChangedPlugins() {
    let plugins = [];
    let info = Editor.Package.getPackages();
    // console.log(JSON.stringify(info));
    for (const key in pluginsConfig) {
        if (Object.prototype.hasOwnProperty.call(pluginsConfig, key)) {
            const config = pluginsConfig[key].config;
            for (let j = 0; j < info.length; j++) {
                const packageInfo = info[j].info as any;
                // if (packageInfo.name == "plugin-editor") {
                //     console.log(packageInfo.panels);
                // }
                if (packageInfo.name == config.name) {
                    // console.log(packageInfo.name, packageInfo, config);
                    if (isPluginDifferent(packageInfo, config) || isi18nChange(info[j])) {
                        plugins.push(info[j]);
                    }
                }
            }
        }
    }
    return plugins;
}

function isPluginDifferent(packageInfo: any, config: any) {
    if (packageInfo.description != config.description) {
        console.log("config change: description");
        return true;
    }
    // if (packageInfo.panels && !config.panels) {
    //     console.log("config change: panels");
    //     return true;
    // };
    // if (!packageInfo.panels && config.panels) {
    //     console.log("config change: panels");
    //     return true
    // };
    if (isExistDifferent(packageInfo.panels, config.panels)) {
        console.log("config change: panels 1");
        return true;
    }
    if (packageInfo.panels && config.panels) {
        if (isObjectKeysDifferent(packageInfo.panels, config.panels)) {
            console.log("config change: panels 2");
            return true;
        }
        for (const key in packageInfo.panels) {
            if (isObjectChildDiffrent(packageInfo.panels[key], config.panels[key], ["title", "type", "size"])) {
                console.log("config change: panels 3");
                return true;
            }
        }
    }
    // if (packageInfo.panels) {
    //     for (const panel in packageInfo.panels) {
    //         if (Object.prototype.hasOwnProperty.call(config.panels, panel)) {
    //             if (packageInfo.panels[panel].title != config.panels[panel].title) {
    //                 console.log("config change: panels title");
    //                 return true;
    //             }
    //             if (packageInfo.panels[panel].type != config.panels[panel].type) {
    //                 console.log("config change: panels type");
    //                 return true;
    //             }
    //             if (packageInfo.panels[panel].size["min-width"] != config.panels[panel].size["min-width"]) {
    //                 console.log("config change: panels min-width");
    //                 return true;
    //             }
    //             if (packageInfo.panels[panel].size["min-height"] != config.panels[panel].size["min-height"]) {
    //                 console.log("config change: panels min-height");
    //                 return true;
    //             }
    //             if (packageInfo.panels[panel].size["width"] != config.panels[panel].size["width"]) {
    //                 console.log("config change: panels width");
    //                 return true;
    //             }
    //             if (packageInfo.panels[panel].size["height"] != config.panels[panel].size["height"]) {
    //                 console.log("config change: panels height");
    //                 return true;
    //             }
    //         }
    //     }
    // }

    // if (packageInfo.contributions && !config.contributions) {
    //     console.log("config change: contributions");
    //     return true;
    // };
    // if (!packageInfo.contributions && config.contributions) {
    //     console.log("config change: contributions");
    //     return true;
    // };
    if (isExistDifferent(packageInfo.contributions, config.contributions)) {
        console.log("config change: contributions");
        return true;
    }
    if (packageInfo.contributions && config.contributions) {
        if (isObjectKeysDifferent(packageInfo.contributions, config.contributions)) {
            console.log("config change: panels");
            return true;
        }
        // if (packageInfo.contributions.menu && !config.contributions.menu) {
        //     console.log("config change: contributions menu");
        //     return true;
        // };
        // if (!packageInfo.contributions.menu && config.contributions.menu) {
        //     console.log("config change: contributions menu");
        //     return true;
        // };
        if (isExistDifferent(packageInfo.contributions.menu, config.contributions.menu)) {
            console.log("config change: contributions.menu");
            return true;
        }
        if (packageInfo.contributions.menu && config.contributions.menu) {
            if (packageInfo.contributions.menu.length != config.contributions.menu.length) {
                console.log("config change: contributions.menu");
                return true;
            }
            for (let i = 0; i < packageInfo.contributions.menu.length; i++) {
                const menu = packageInfo.contributions.menu[i];
                if (menu.path != config.contributions.menu[i].path) {
                    console.log("config change: contributions menu path");
                    return true;
                }
                if (menu.label != config.contributions.menu[i].label) {
                    console.log("config change: contributions menu label");
                    return true;
                }
                if (menu.message && menu.message.name != config.contributions.menu[i].message) {
                    console.log("config change: contributions menu message");
                    return true;
                }
            }
        }

        // if (packageInfo.contributions.messages && !config.contributions.messages) {
        //     console.log("config change: contributions messages");
        //     return true;
        // };
        // if (!packageInfo.contributions.messages && config.contributions.messages) {
        //     console.log("config change: contributions messages");
        //     return true;
        // };
        if (isExistDifferent(packageInfo.contributions.messages, config.contributions.messages)) {
            console.log("config change: contributions.messages");
            return true;
        }
        if (packageInfo.contributions.messages && config.contributions.messages) {
            if (isValueDifferent(packageInfo.contributions.messages, config.contributions.messages)) {
                console.log("config change: contributions.messages", packageInfo.contributions.messages, config.contributions.messages);
                return true;
            }
            // if (!isArraySame(Object.keys(packageInfo.contributions.messages), Object.keys(config.contributions.messages))) {
            //     return true;
            // }
            // for (const k in packageInfo.contributions.messages) {
            //     if (Object.prototype.hasOwnProperty.call(packageInfo.contributions.messages, k)) {
            //         const packageMessage = packageInfo.contributions.messages[k];
            //         if (Object.prototype.hasOwnProperty.call(config.contributions.messages, k)) {
            //             const configMessage = config.contributions.messages[k];
            //             if (packageMessage.methods && !configMessage.methods) {
            //                 console.log("config change: contributions messages methods");
            //                 return true;
            //             };
            //             if (!packageMessage.methods && configMessage.methods) {
            //                 console.log("config change: contributions messages methods");
            //                 return true;
            //             };
            //             if (packageMessage.methods) {
            //                 if (!isArraySame(packageMessage.methods, configMessage.methods)) {
            //                     console.log("config change: contributions messages methods");
            //                     return true;
            //                 }
            //             }
            //         }
            //     }
            // }
        }
    }
}

async function getPluginsConfig() {
    const files = await readdir(Editor.Project.path + "/extensions");
    for (let i = 0; i < files.length; i++) {
        const file = files[i];
        const stats = await stat(Editor.Project.path + "/extensions/" + file);
        if (stats.isDirectory() && existsSync(Editor.Project.path + "/extensions/" + file + "/package.json")) {
            // let config = require(Editor.Project.path + "/extensions/" + file + "/package.json");
            let configFile = readFileSync(Editor.Project.path + "/extensions/" + file + "/package.json", "utf-8");
            let config = JSON.parse(configFile);
            pluginsConfig[config.name] = { path: Editor.Project.path + "/extensions/" + file, config: config };
        }
    }
    // console.log("getPluginsConfig: ", pluginsConfig);
}

async function getPluginsi18n() {
    const files = await readdir(Editor.Project.path + "/extensions");
    for (let i = 0; i < files.length; i++) {
        const file = files[i];
        const stats = await stat(Editor.Project.path + "/extensions/" + file);
        if (stats.isDirectory() && existsSync(Editor.Project.path + "/extensions/" + file + "/package.json")) {
            // let config = require(Editor.Project.path + "/extensions/" + file + "/package.json");
            let configFile = readFileSync(Editor.Project.path + "/extensions/" + file + "/package.json", "utf-8");
            let config = JSON.parse(configFile);
            pluginsi18n[config.name] = {};
            if (existsSync(Editor.Project.path + "/extensions/" + file + "/i18n/en.js")) {
                let en = readFileSync(Editor.Project.path + "/extensions/" + file + "/i18n/" + "en.js", "utf-8");
                pluginsi18n[config.name].en = en;
            }

            if (existsSync(Editor.Project.path + "/extensions/" + file + "/i18n/zh.js")) {
                let zh = readFileSync(Editor.Project.path + "/extensions/" + file + "/i18n/" + "zh.js", "utf-8");
                pluginsi18n[config.name].zh = zh;
            }
        }
    }
    // console.log("getPluginsi18n: ", pluginsi18n);
}

function isi18nChange(packageDetails: any) {
    if (existsSync(packageDetails.path + "/i18n/en.js")) {
        let en = readFileSync(packageDetails.path + "/i18n/en.js", "utf-8");
        if (pluginsi18n[packageDetails.name].en != en) {
            return true;
        }
    }

    if (existsSync(packageDetails.path + "/i18n/zh.js")) {
        let zh = readFileSync(packageDetails.path + "/i18n/zh.js", "utf-8");
        if (pluginsi18n[packageDetails.name].zh != zh) {
            return true;
        }
    }
}

function isArraySame(a: string | any[], b: string | any[]) {
    if (a.length != b.length) {
        return false;
    }
    for (let i = 0; i < a.length; i++) {
        if (a[i] != b[i]) {
            return false;
        }
    }
    return true;
}

function isExistDifferent(a: any, b: any) {
    if (a == undefined && b != undefined) {
        return true;
    }
    if (a != undefined && b == undefined) {
        return true;
    }
    if (a == null && b != null) {
        return true;
    }
    if (a != null && b == null) {
        return true;
    }
}

function isObjectKeysDifferent(a: any, b: any) {
    if (Object.keys(a).length != Object.keys(b).length) {
        return true;
    }
    for (const key in a) {
        if (!b.hasOwnProperty(key)) {
            return true;
        }
    }
    for (const key in b) {
        if (!a.hasOwnProperty(key)) {
            return true;
        }
    }
}

function isObjectChildDiffrent(a: any, b: any, keys: string[]) {
    for (const key of keys) {
        if (isValueDifferent(a[key], b[key])) {
            return true;
        }
    }
}

function isValueDifferent(a: any, b: any) {
    if (typeof a !== typeof b) return true;
    if (typeof a === 'object') {
        if (a === null && b !== null) return true;
        if (a !== null && b === null) return true;
        if (a === null && b === null) {
            return false;
        }

        if(isObjectKeysDifferent(a, b)) {
            return true;
        }
        for (const key in a) {
            if (isValueDifferent(a[key], b[key])) {
                console.log("isValueDifferent: ", a[key], b[key], isValueDifferent(a[key], b[key]));
                return true;
            }
        }
    } else if (typeof a == "number" || typeof a === 'string' || typeof a === 'boolean') {
        if (a != b) {
            return true;
        }
    } else {
        if (a === undefined && b !== undefined) return true;
        if (a !== undefined && b === undefined) return true;
    }
    
    return false;
}
