/**
 * Replace most of this, once we generate the relevant plugin-data for the workbench
 */

import { forEachObjIndexed } from "ramda"
import type { ConfigurableParameters, WidgetConf } from "@racletteOrchestrator"
import { generatePluginKey } from "@shared/helper/pluginHelper"
import type { PluginMetadata } from "@core"
import type { RegisteredWidgetDeclaration, WidgetDeclaration } from "@racletteOrchestrator"
import { normalizeWidgetVisuals } from "@racletteOrchestrator/helpers"

// Plugin metadata files (unchanged)
const RACLETTE_PLUGIN_FILES = import.meta.glob<{
  default: PluginMetadata
}>(["@racletteCore/../../external-app-plugins/**/raclette.plugin.ts"], {
  eager: true,
})

const EXTERNAL_PLUGIN_FRONTEND_INDEX_KEYS = new Set(
  Object.keys(
    import.meta.glob(
      "@racletteCore/../../external-app-plugins/**/frontend/index.ts",
      {
        eager: false,
      },
    ),
  ),
)

function resolveExternalPluginFrontendPath(
  pluginDir: string,
  metadata: PluginMetadata,
): string {
  const explicit = metadata.frontendDir?.replace(/^\.\//, "")
  if (explicit) {
    return `${pluginDir}/${explicit}`
  }

  const direct = `${pluginDir}/frontend`
  const underSrc = `${pluginDir}/src/frontend`
  const directIndex = `${direct}/index.ts`
  const srcIndex = `${underSrc}/index.ts`

  const hasDirect = EXTERNAL_PLUGIN_FRONTEND_INDEX_KEYS.has(directIndex)
  const hasUnderSrc = EXTERNAL_PLUGIN_FRONTEND_INDEX_KEYS.has(srcIndex)

  if (hasDirect && hasUnderSrc) {
    return direct
  }
  if (hasUnderSrc) {
    return underSrc
  }
  return direct
}

// Discover widget Vue files to get widget names
const WIDGET_COMPONENT_FILES = import.meta.glob(
  [
    "@racletteCore/../../external-app-plugins/**/frontend/widgets/**/*Widget.vue",
  ],
  {
    eager: false,
    as: "url",
  },
)

// Discover widget setup files for metadata
const WIDGET_SETUP_FILES = import.meta.glob<{
  details: any
  config: any
  default: { details: any; config: any }
}>(
  ["@racletteCore/../../external-app-plugins/**/frontend/widgets/**/setup.ts"],
  {
    eager: true,
  },
)

/**
 * Extract widget name from Vue component file path
 * /path/to/widgets/ServerListWidget.vue -> ServerList
 * /path/to/widgets/MyCustomWidget.vue -> MyCustom
 */
const extractWidgetNameFromVueFile = (componentPath: string): string | null => {
  // Match the file name and remove "Widget.vue"
  const match = componentPath.match(/\/([^/]+)Widget\.vue$/)
  return match ? match[1] : null
}

/**
 * Get widget declarations by discovering Vue files and their corresponding setup files
 */
export const getWidgetDeclacations = () => {
  const widgets: RegisteredWidgetDeclaration[] = []

  // Process each plugin
  forEachObjIndexed(({ default: pluginMetadata }, pluginPath) => {
    const pluginKey = generatePluginKey(
      pluginMetadata.name,
      pluginMetadata.author,
    )

    // Find all widget component files for this plugin
    const pluginDir = pluginPath.replace("/raclette.plugin.ts", "")
    const frontendPath = resolveExternalPluginFrontendPath(
      pluginDir,
      pluginMetadata,
    )
    const widgetPattern = `${frontendPath}/widgets/`

    // Look through all discovered widget Vue files to find ones belonging to this plugin
    Object.keys(WIDGET_COMPONENT_FILES).forEach((componentPath) => {
      if (componentPath.includes(widgetPattern)) {
        // Extract widget name from Vue file name
        const widgetName = extractWidgetNameFromVueFile(componentPath)
        if (!widgetName) {
          console.warn(`Could not extract widget name from: ${componentPath}`)
          return
        }

        // Find corresponding setup file
        // /path/to/widgets/SomeDir/ServerListWidget.vue -> /path/to/widgets/SomeDir/setup.ts
        const setupPath = componentPath.replace(
          /\/[^/]+Widget\.vue$/,
          "/setup.ts",
        )
        const setupModule = WIDGET_SETUP_FILES[setupPath]

        if (!setupModule) {
          console.warn(
            `No setup.ts found for widget: ${pluginKey}/${widgetName} at ${setupPath}`,
          )
          return
        }

        // Extract details and config (handle both default export and named exports)
        const details = (setupModule.details || setupModule.default?.details) as
          | WidgetDeclaration
          | undefined
        const config = setupModule.config || setupModule.default?.config

        if (!details) {
          console.warn(
            `No widget details found in setup for: ${pluginKey}/${widgetName}`,
          )
          return
        }

        const normalizedVisuals = normalizeWidgetVisuals(details, widgetName)
        const registeredWidget: RegisteredWidgetDeclaration = {
          ...details,
          ...normalizedVisuals,
          pluginKey,
          author: pluginMetadata.author,
          name: widgetName,
        }

        if (config && Object.keys(config).length > 0) {
          registeredWidget.configurableParameters = getConfigurableParameters(
            registeredWidget,
            config,
          )
        }

        widgets.push(registeredWidget)
      }
    })
  }, RACLETTE_PLUGIN_FILES)

  return widgets
}

/**
 * Updated getWidgetConfig to work with setup files
 */
export const getWidgetConfig = (widgetName: string, pluginKey?: string) => {
  if (!pluginKey) {
    return {}
  }

  // Find the setup file for this widget
  const setupPath = findSetupPathForWidget(widgetName, pluginKey)
  if (!setupPath) {
    return {}
  }

  try {
    const setupModule = WIDGET_SETUP_FILES[setupPath]
    const config = setupModule?.config || setupModule?.default?.config
    return config || {}
  } catch (error) {
    console.warn(
      `Error loading widget config for ${pluginKey}/${widgetName}:`,
      error,
    )
    return {}
  }
}

/**
 * Find setup.ts path for a specific widget and plugin
 */
const findSetupPathForWidget = (
  widgetName: string,
  pluginKey: string,
): string | null => {
  // Find the plugin metadata to get the plugin path
  const pluginEntry = Object.entries(RACLETTE_PLUGIN_FILES).find(
    ([, module]) => {
      const metadata = module.default
      return generatePluginKey(metadata.name, metadata.author) === pluginKey
    },
  )

  if (!pluginEntry) {
    return null
  }

  const [pluginPath, pluginModule] = pluginEntry
  const pluginDir = pluginPath.replace("/raclette.plugin.ts", "")
  const metadata = pluginModule.default
  const frontendPath = resolveExternalPluginFrontendPath(pluginDir, metadata)

  // Look for a Vue file with this widget name to find the directory structure
  const widgetPattern = `${frontendPath}/widgets/`
  const widgetVueFile = Object.keys(WIDGET_COMPONENT_FILES).find(
    (path) =>
      path.includes(widgetPattern) && path.endsWith(`${widgetName}Widget.vue`),
  )

  if (!widgetVueFile) {
    return null
  }

  // Convert Vue file path to setup path
  const setupPath = widgetVueFile.replace(/\/[^/]+Widget\.vue$/, "/setup.ts")

  // Check if this setup file exists
  return Object.keys(WIDGET_SETUP_FILES).includes(setupPath) ? setupPath : null
}

export const getDefaultConfig = (widgetName: string, pluginKey: string) => {
  const props = getWidgetConfig(widgetName, pluginKey)

  if (props) {
    return convertToDefaultConfig(props)
  }
}

export const getConfigurableParameters = (
  widgetDeclaration: RegisteredWidgetDeclaration,
  widgetConf?: WidgetConf,
) => {
  const { name, pluginKey } = widgetDeclaration

  const config = widgetConf || getWidgetConfig(name, pluginKey)

  if (config) {
    return convertToConfigurableParameters(config)
  }
}

export const convertToDefaultConfig = (props: WidgetConf) => {
  const defaultConfig: Record<string, any> = {}

  forEachObjIndexed(({ default: defaultValue }, key) => {
    defaultConfig[key] = normalizeDefaultValue(defaultValue)
  }, props)

  return defaultConfig
}

export const convertToConfigurableParameters = (config: WidgetConf) => {
  const parameters: ConfigurableParameters = {}

  forEachObjIndexed(({ default: defaultValue, editor }, key) => {
    parameters[key] = {
      ...editor,
      defaultValue: normalizeDefaultValue(defaultValue),
    }
  }, config)

  return parameters
}

export const normalizeDefaultValue = (
  defaultValue: WidgetConf[keyof WidgetConf]["default"],
) => (typeof defaultValue === "function" ? defaultValue() : defaultValue)
