import { generatePluginKey } from "@shared/helper/pluginHelper"
import logger from "@racletteCore/lib/logger"
import configService from "@racletteCore/lib/configService"
import { validatePluginMetadata } from "../utils/operations"
import type { DiscoveredPlugin, PluginType } from "../types"

/**
 * Discover npm plugins from configuration
 */
export const discoverNpmPlugins = async (): Promise<DiscoveredPlugin[]> => {
  const plugins: DiscoveredPlugin[] = []
  const installedPlugins = configService.getPlugins()

  if (!installedPlugins.length) {
    return plugins
  }

  logger.pluginRegistrar(
    `Discovering ${installedPlugins.length} npm plugin(s)...`,
  )

  // Create static glob patterns for all possible npm plugin locations
  const nodeModulesGlob = import.meta.glob(
    "/node_modules/*/raclette.plugin.ts",
    { eager: false },
  )

  const devMountGlob = import.meta.glob(
    "/mountedPlugins/*/raclette.plugin.ts",
    {
      eager: false,
    },
  )

  // Combine all glob results
  const allNpmConfigs = {
    ...nodeModulesGlob,
    ...devMountGlob,
  }

  for (const pluginPackage of installedPlugins) {
    try {
      const pluginNameWithoutScope = pluginPackage.replace(/^@[^/]+\//, "")

      // Find matching config path
      let foundConfigPath: string | null = null
      let foundMetadata: any = null
      let foundPluginPath: string | null = null

      // Check all discovered configs for a match
      for (const configPath of Object.keys(allNpmConfigs)) {
        if (
          configPath.includes(
            `/node_modules/${pluginPackage}/raclette.plugin.ts`,
          ) ||
          (configPath.includes(`/node_modules/@`) &&
            configPath.includes(
              `/${pluginPackage.split("/")[1]}/raclette.plugin.ts`,
            )) ||
          configPath.includes(`/${pluginNameWithoutScope}/raclette.plugin.ts`)
        ) {
          try {
            const configModule = await allNpmConfigs[configPath]()
            const metadata = (configModule as any)?.default || configModule

            if (validatePluginMetadata(metadata)) {
              foundConfigPath = configPath
              foundMetadata = metadata
              foundPluginPath = configPath.replace(
                /\/raclette\.plugin\.ts$/,
                "",
              )
              logger.pluginRegistrar("Found npm plugin config at", configPath)
              break
            }
          } catch (error) {
            continue
          }
        }
      }

      if (!foundMetadata || !foundConfigPath || !foundPluginPath) {
        logger.pluginRegistrar(
          `Could not find valid npm plugin: ${pluginPackage}`,
        )
        continue
      }

      // Determine frontend path
      const frontendRelativePath = foundMetadata.frontendDir || "src/frontend"
      const frontendPath = `${foundPluginPath}/${frontendRelativePath}`

      const pluginKey = generatePluginKey(
        foundMetadata.name,
        foundMetadata.author,
      )

      plugins.push({
        configPath: foundConfigPath,
        pluginPath: foundPluginPath,
        frontendPath,
        type: "npm" as PluginType,
        metadata: foundMetadata,
        pluginKey,
      })

      logger.pluginRegistrar("Discovered npm plugin:", pluginKey)
    } catch (error) {
      logger.pluginRegistrar(
        `Error processing npm plugin ${pluginPackage}:`,
        error,
      )
    }
  }

  return plugins
}
