import logger from "@racletteCore/lib/logger"
import { getPluginWidgets } from "@racletteOrchestrator/helpers/staticWidgetRegistry"
import { discoverAllPlugins } from "../discovery"
import {
  registeredPlugins,
  addRegisteredPlugin,
  addPluginPathMapping,
} from "../state"
import {
  wrapLogApi,
  wrapFileApi,
  wrapEventbusApi,
  wrapSocketApi,
} from "../api/wrappers"
import {
  installPluginData,
  handlePluginOperations,
  updateTranslations,
} from "../api/plugin-data"
import { loadPluginDefinition } from "./loader"
import { handlePluginError } from "./error-handling"
import type { CorePluginApi, RegisteredPlugin } from "@racletteCore"
import { DEFAULT_ERROR_FLAGS } from "../constants"
import type { DiscoveredPlugin, PluginApi } from "../types"

/**
 * Main plugin registration function
 */
export const registerPlugins = async (
  corePluginApi: CorePluginApi,
  errorFlags: number = DEFAULT_ERROR_FLAGS,
): Promise<{ [key: string]: RegisteredPlugin }> => {
  let registeredCount = 0

  try {
    // Discover all plugins
    const allPlugins = await discoverAllPlugins()

    logger.pluginRegistrar(`Found ${allPlugins.length} plugins total`)

    // Register each plugin
    for (const plugin of allPlugins) {
      try {
        const success = await loadAndRegisterPlugin(
          plugin,
          corePluginApi,
          errorFlags,
        )

        if (success) {
          registeredCount++
          logger.pluginRegistrar(
            `Successfully registered ${plugin.type} plugin: ${plugin.pluginKey}`,
          )
        }
      } catch (error) {
        const errorMsg = `Error registering ${plugin.type} plugin ${plugin.pluginKey}: ${(error as Error).message}`
        handlePluginError(errorMsg, plugin.type, errorFlags)
      }
    }

    logger.pluginRegistrar(`Total plugins registered: ${registeredCount}`)
    return registeredPlugins
  } catch (error) {
    logger.pluginRegistrar("Critical error during plugin registration:", error)
    throw error
  }
}

/**
 * Load and register a single plugin
 */
export const loadAndRegisterPlugin = async (
  plugin: DiscoveredPlugin,
  corePluginApi: CorePluginApi,
  errorFlags: number,
): Promise<boolean> => {
  try {
    // Load plugin definition from frontend directory
    const pluginDefinition = await loadPluginDefinition(plugin.frontendPath)
    if (!pluginDefinition) {
      const error = `No plugin definition found for ${plugin.pluginKey}`
      handlePluginError(error, plugin.type, errorFlags)
      return false
    }

    // Initialize plugin entry
    if (!registeredPlugins[plugin.pluginKey]) {
      const newPlugin: RegisteredPlugin = {
        author: plugin.metadata.author,
        pluginKey: plugin.pluginKey,
        pluginType: plugin.type,
        path: plugin.pluginPath,
        widgets: getPluginWidgets(plugin.frontendPath),
        options: {},
      }
      addRegisteredPlugin(plugin.pluginKey, newPlugin)
    }

    const currentPlugin = registeredPlugins[plugin.pluginKey]
    addPluginPathMapping(plugin.pluginPath, plugin.pluginKey)

    let pluginApi: Partial<PluginApi> & { [key: string]: unknown } = {}

    // Initialize plugin API components
    if (corePluginApi.$log) {
      pluginApi = wrapLogApi(corePluginApi.$log, plugin.pluginKey, pluginApi)
    }

    if (corePluginApi.$file) {
      pluginApi = wrapFileApi(corePluginApi.$file, pluginApi)
    }

    if (corePluginApi.$eventbus) {
      currentPlugin.initEventbus = () =>
        wrapEventbusApi(plugin, corePluginApi.$eventbus, pluginApi)
    }

    const handleOperations = handlePluginOperations(
      plugin.pluginKey,
      pluginApi.$log,
    )

    if (pluginDefinition.i18n) {
      updateTranslations(
        plugin.pluginKey,
        pluginDefinition.i18n,
        pluginApi.$log,
      )
    }

    currentPlugin.initCud = (
      pluginObservableWrapper: any,
      instanceId: string,
      actionIdOverride = "",
    ) => {
      return handleOperations(
        actionIdOverride,
        pluginObservableWrapper,
        instanceId,
        pluginDefinition.data,
      )
    }

    currentPlugin.initSocket = () => {
      return wrapSocketApi(currentPlugin, corePluginApi.$socket)
    }

    // Run plugin install function if it exists
    if (
      pluginDefinition.install &&
      typeof pluginDefinition.install === "function"
    ) {
      pluginApi.$log?.("called plugin install func")
      const customEndpoints = await pluginDefinition.install(
        installPluginData(corePluginApi.$store, pluginApi.$log),
        corePluginApi,
      )

      if (
        customEndpoints &&
        typeof customEndpoints === "object" &&
        Object.keys(customEndpoints)?.length
      ) {
        pluginApi.$log?.("added custom Endpoints", customEndpoints)
        pluginApi = { ...pluginApi, ...customEndpoints }
      }
    }

    pluginApi.$log?.("Registered plugin", registeredPlugins[plugin.pluginKey])
    registeredPlugins[plugin.pluginKey].$api = pluginApi

    return true
  } catch (error) {
    logger.pluginRegistrar(`Error loading plugin ${plugin.pluginKey}:`, error)
    return false
  }
}

export * from "./loader"
export * from "./error-handling"
