import { EditorPluginManager, LocaleService, MessageHub } from '@esengine/editor-core';
import type { IEditorPlugin } from '@esengine/editor-core';
import { Core } from '@esengine/ecs-framework';
import { TauriAPI } from '../api/tauri';

interface PluginPackageJson {
    name: string;
    version: string;
    main?: string;
    module?: string;
    exports?: {
        '.': {
            import?: string;
            require?: string;
            development?: {
                types?: string;
                import?: string;
            };
        }
    };
}

export class PluginLoader {
    private loadedPluginNames: Set<string> = new Set();

    async loadProjectPlugins(projectPath: string, pluginManager: EditorPluginManager): Promise<void> {
        const pluginsPath = `${projectPath}/plugins`;

        try {
            const exists = await TauriAPI.pathExists(pluginsPath);
            if (!exists) {
                console.log('[PluginLoader] No plugins directory found');
                return;
            }

            const entries = await TauriAPI.listDirectory(pluginsPath);
            const pluginDirs = entries.filter((entry) => entry.is_dir && !entry.name.startsWith('.'));
            console.log('[PluginLoader] Found plugin directories:', pluginDirs.map((d) => d.name));

            for (const entry of pluginDirs) {
                const pluginPath = `${pluginsPath}/${entry.name}`;
                await this.loadPlugin(pluginPath, entry.name, pluginManager);
            }
        } catch (error) {
            console.error('[PluginLoader] Failed to load project plugins:', error);
        }
    }

    private async loadPlugin(pluginPath: string, pluginDirName: string, pluginManager: EditorPluginManager): Promise<void> {
        try {
            const packageJsonPath = `${pluginPath}/package.json`;
            const packageJsonExists = await TauriAPI.pathExists(packageJsonPath);

            if (!packageJsonExists) {
                console.warn(`[PluginLoader] No package.json found in ${pluginPath}`);
                return;
            }

            const packageJsonContent = await TauriAPI.readFileContent(packageJsonPath);
            const packageJson: PluginPackageJson = JSON.parse(packageJsonContent);

            if (this.loadedPluginNames.has(packageJson.name)) {
                try {
                    await pluginManager.uninstallEditor(packageJson.name);
                    this.loadedPluginNames.delete(packageJson.name);
                } catch (error) {
                    console.error(`[PluginLoader] Failed to uninstall existing plugin ${packageJson.name}:`, error);
                }
            }

            let entryPoint = 'src/index.ts';

            if (packageJson.exports?.['.']?.development?.import) {
                entryPoint = packageJson.exports['.'].development.import;
            } else if (packageJson.exports?.['.']?.import) {
                const importPath = packageJson.exports['.'].import;
                if (importPath.startsWith('src/')) {
                    entryPoint = importPath;
                } else {
                    const srcPath = importPath.replace('dist/', 'src/').replace('.js', '.ts');
                    const srcExists = await TauriAPI.pathExists(`${pluginPath}/${srcPath}`);
                    entryPoint = srcExists ? srcPath : importPath;
                }
            } else if (packageJson.module) {
                const srcPath = packageJson.module.replace('dist/', 'src/').replace('.js', '.ts');
                const srcExists = await TauriAPI.pathExists(`${pluginPath}/${srcPath}`);
                entryPoint = srcExists ? srcPath : packageJson.module;
            } else if (packageJson.main) {
                const srcPath = packageJson.main.replace('dist/', 'src/').replace('.js', '.ts');
                const srcExists = await TauriAPI.pathExists(`${pluginPath}/${srcPath}`);
                entryPoint = srcExists ? srcPath : packageJson.main;
            }

            // 移除开头的 ./
            entryPoint = entryPoint.replace(/^\.\//, '');

            // 添加时间戳参数强制重新加载模块（避免缓存）
            const timestamp = Date.now();
            const moduleUrl = `/@user-project/plugins/${pluginDirName}/${entryPoint}?t=${timestamp}`;

            console.log(`[PluginLoader] Loading plugin from: ${moduleUrl}`);

            const module = await import(/* @vite-ignore */ moduleUrl);
            console.log('[PluginLoader] Module loaded successfully');

            let pluginInstance: IEditorPlugin | null = null;
            try {
                pluginInstance = this.findPluginInstance(module);
            } catch (findError) {
                console.error('[PluginLoader] Error finding plugin instance:', findError);
                console.error('[PluginLoader] Module object:', module);
                return;
            }

            if (!pluginInstance) {
                console.error(`[PluginLoader] No plugin instance found in ${packageJson.name}`);
                return;
            }

            await pluginManager.installEditor(pluginInstance);
            this.loadedPluginNames.add(packageJson.name);

            // 同步插件的语言设置
            try {
                const localeService = Core.services.resolve(LocaleService);
                const currentLocale = localeService.getCurrentLocale();
                if (pluginInstance.setLocale) {
                    pluginInstance.setLocale(currentLocale);
                    console.log(`[PluginLoader] Set locale for plugin ${packageJson.name}: ${currentLocale}`);
                }
            } catch (error) {
                console.warn(`[PluginLoader] Failed to set locale for plugin ${packageJson.name}:`, error);
            }

            // 通知节点面板重新加载模板
            try {
                const messageHub = Core.services.resolve(MessageHub);
                const localeService = Core.services.resolve(LocaleService);
                messageHub.publish('locale:changed', { locale: localeService.getCurrentLocale() });
                console.log(`[PluginLoader] Published locale:changed event for plugin ${packageJson.name}`);
            } catch (error) {
                console.warn('[PluginLoader] Failed to publish locale:changed event:', error);
            }

            console.log(`[PluginLoader] Successfully loaded plugin: ${packageJson.name}`);
        } catch (error) {
            console.error(`[PluginLoader] Failed to load plugin from ${pluginPath}:`, error);
            if (error instanceof Error) {
                console.error('[PluginLoader] Error stack:', error.stack);
            }
        }
    }

    private findPluginInstance(module: any): IEditorPlugin | null {
        console.log('[PluginLoader] Module exports:', Object.keys(module));

        if (module.default && this.isPluginInstance(module.default)) {
            console.log('[PluginLoader] Found plugin in default export');
            return module.default;
        }

        for (const key of Object.keys(module)) {
            const value = module[key];
            if (value && this.isPluginInstance(value)) {
                console.log(`[PluginLoader] Found plugin in export: ${key}`);
                return value;
            }
        }

        console.error('[PluginLoader] No valid plugin instance found. Exports:', module);
        return null;
    }

    private isPluginInstance(obj: any): obj is IEditorPlugin {
        try {
            if (!obj || typeof obj !== 'object') {
                return false;
            }

            const hasRequiredProperties =
                typeof obj.name === 'string' &&
                typeof obj.version === 'string' &&
                typeof obj.displayName === 'string' &&
                typeof obj.category === 'string' &&
                typeof obj.install === 'function' &&
                typeof obj.uninstall === 'function';

            if (!hasRequiredProperties) {
                console.log('[PluginLoader] Object is not a valid plugin:', {
                    hasName: typeof obj.name === 'string',
                    hasVersion: typeof obj.version === 'string',
                    hasDisplayName: typeof obj.displayName === 'string',
                    hasCategory: typeof obj.category === 'string',
                    hasInstall: typeof obj.install === 'function',
                    hasUninstall: typeof obj.uninstall === 'function',
                    objectType: typeof obj,
                    objectConstructor: obj?.constructor?.name
                });
            }

            return hasRequiredProperties;
        } catch (error) {
            console.error('[PluginLoader] Error in isPluginInstance:', error);
            return false;
        }
    }

    async unloadProjectPlugins(pluginManager: EditorPluginManager): Promise<void> {
        for (const pluginName of this.loadedPluginNames) {
            try {
                await pluginManager.uninstallEditor(pluginName);
            } catch (error) {
                console.error(`[PluginLoader] Failed to unload plugin ${pluginName}:`, error);
            }
        }
        this.loadedPluginNames.clear();
    }
}
