import { ref, type Ref } from "vue"
import { isDevelopmentMode } from "@racletteCore/helpers/devMode"
import log from "@racletteCore/lib/logger"

export type OnAllWidgetsReady = (callback: () => void) => void

interface WidgetLifecycleHooks {
  onAllWidgetsReady: OnAllWidgetsReady
  onWidgetRendered: (element: HTMLElement) => void
  onWidgetUnmounted: () => void
}

interface WidgetLifecycleManager {
  createLifecycleHooks: (widgetId: string) => WidgetLifecycleHooks
  allWidgetsReady: Ref<boolean>
  reset: () => void
}

export function createWidgetLifecycleManager(
  totalWidgets: number,
): WidgetLifecycleManager {
  const renderedWidgets = ref(new Set<string>())
  const allWidgetsReady = ref(false)
  const readyCallbacks = new Set<() => void>()
  const observers = new Map<string, MutationObserver>()

  const DEV_MODE = isDevelopmentMode()

  const checkAllReady = () => {
    if (renderedWidgets.value.size === totalWidgets && !allWidgetsReady.value) {
      allWidgetsReady.value = true

      if (DEV_MODE) {
        log.widgets(
          "useWidgetLifecycle",
          `✅ All ${totalWidgets} widgets are fully rendered`,
        )
      }

      readyCallbacks.forEach((callback) => callback())
      readyCallbacks.clear()
    }
  }

  const hasVisibleContent = (element: HTMLElement): boolean => {
    // Check if element has any child nodes
    if (element.childNodes.length === 0) {
      return false
    }

    // Check if element has visible dimensions
    const rect = element.getBoundingClientRect()
    if (rect.width === 0 && rect.height === 0) {
      return false
    }

    // Check for text content or child elements
    const hasTextContent = element.textContent?.trim().length > 0
    const hasChildElements = element.children.length > 0

    return hasTextContent || hasChildElements
  }

  const registerWidgetAsRendered = (id: string) => {
    if (!renderedWidgets.value.has(id)) {
      renderedWidgets.value.add(id)

      if (DEV_MODE) {
        log.widgets(
          "useWidgetLifecycle",
          `📦 Widget rendered: ${id} (${renderedWidgets.value.size}/${totalWidgets})`,
        )
      }

      checkAllReady()
    }
  }

  const unregisterWidget = (id: string) => {
    if (DEV_MODE) {
      log.widgets("useWidgetLifecycle", `📤 Widget unregistered: ${id}`)
    }

    // Clean up observer
    const observer = observers.get(id)
    if (observer) {
      observer.disconnect()
      observers.delete(id)
    }

    renderedWidgets.value.delete(id)

    if (renderedWidgets.value.size < totalWidgets) {
      allWidgetsReady.value = false
    }
  }

  const observeWidgetRendering = (id: string, element: HTMLElement) => {
    // Check immediately if content is already rendered
    if (hasVisibleContent(element)) {
      registerWidgetAsRendered(id)
      return
    }

    // Otherwise, observe for changes
    const observer = new MutationObserver(() => {
      if (hasVisibleContent(element)) {
        registerWidgetAsRendered(id)
        observer.disconnect()
        observers.delete(id)
      }
    })

    observer.observe(element, {
      childList: true,
      subtree: true,
      characterData: true,
      attributes: true,
      attributeFilter: ["style", "class"],
    })

    observers.set(id, observer)

    if (DEV_MODE) {
      log.widgets(
        "useWidgetLifecycle",
        `👀 Observing widget for content: ${id}`,
      )
    }
  }

  const createLifecycleHooks = (widgetId: string): WidgetLifecycleHooks => ({
    onAllWidgetsReady: (callback: () => void) => {
      if (allWidgetsReady.value) {
        callback()
      } else {
        readyCallbacks.add(callback)
      }
    },
    onWidgetRendered: (element: HTMLElement) => {
      observeWidgetRendering(widgetId, element)
    },
    onWidgetUnmounted: () => unregisterWidget(widgetId),
  })

  const reset = () => {
    // Disconnect all observers
    observers.forEach((observer) => observer.disconnect())
    observers.clear()
    renderedWidgets.value.clear()
    allWidgetsReady.value = false
    readyCallbacks.clear()

    if (DEV_MODE) {
      log.widgets("useWidgetLifecycle", "🔄 Widget lifecycle manager reset")
    }
  }

  return {
    createLifecycleHooks,
    allWidgetsReady,
    reset,
  }
}
