import type { WidgetBase } from "@racletteCore/store/types"
import type { Component } from "vue"
import { defineAsyncComponent, h } from "vue"
import log from "@racletteCore/lib/logger"
import { loadWidgetComponent } from "./staticWidgetRegistry"
import LoadingWidgetState from "@racletteOrchestrator/components/LoadingWidgetState.vue"
import ErrorWidgetState from "@racletteOrchestrator/components/ErrorWidgetState.vue"
import { createErrorBoundary } from "./errorBoundary"
import { validateWidget, createEnhancedError } from "./widgetUtils"

export type WidgetLoaderOptions = {
  loadingComponent?: Component
  errorComponent?: Component
  timeout?: number
  delay?: number
}

/**
 * Enhanced widget loader that returns a Vue async component with built-in loading and error states
 */
export const widgetLoader = (
  widget: Partial<WidgetBase>,
  options: WidgetLoaderOptions = {},
) => {
  log.widgets("widgetLoader called", {
    pluginKey: widget.pluginKey,
    name: widget.name,
  })

  const {
    loadingComponent = LoadingWidgetState,
    errorComponent = ErrorWidgetState,
    timeout = 10000,
    delay = 0,
  } = options

  return defineAsyncComponent({
    loader: async () => {
      try {
        validateWidget(widget)

        const originalComponent = await loadWidgetComponent(
          widget.pluginKey!,
          widget.name!,
        )

        if (!originalComponent) {
          throw new Error(
            `Widget component is null/undefined after loading: ${widget.pluginKey}/${widget.name}`,
          )
        }

        validateVueComponent(originalComponent)

        log.widgets("Successfully loaded component", {
          pluginKey: widget.pluginKey,
          name: widget.name,
        })

        return createErrorBoundary(originalComponent, widget, errorComponent)
      } catch (error) {
        const enhancedError = createEnhancedError(error, widget)
        log.widgets("Failed to load widget", {
          pluginKey: widget.pluginKey,
          name: widget.name,
          error: enhancedError.message,
        })
        throw enhancedError
      }
    },
    loadingComponent,
    errorComponent: createSafeErrorComponent(widget, errorComponent),
    delay,
    timeout,
  })
}

const validateVueComponent = (component: unknown) => {
  if (typeof component !== "object" && typeof component !== "function") {
    throw new Error(
      `Widget component is not a valid Vue component: ${typeof component}`,
    )
  }
}

const createSafeErrorComponent = (
  widget: Partial<WidgetBase>,
  errorComponent: Component,
) => ({
  name: "SafeWidgetError",
  props: ["error"],
  setup(errorProps: { error: Error }) {
    try {
      return () =>
        h(errorComponent, {
          uuid: widget.uuid,
          pluginKey: widget.pluginKey,
          widgetName: widget.name,
          error: errorProps.error,
        })
    } catch (e) {
      log.widgets("Error in error component", {
        pluginKey: widget.pluginKey,
        name: widget.name,
        error: e instanceof Error ? e.message : String(e),
      })

      return () =>
        h(
          "div",
          {
            class: "p-4 text-red-500 border border-red-300 rounded",
          },
          `Error loading error component for ${widget.pluginKey}/${widget.name}`,
        )
    }
  },
})
