<template>
  <div
    class="tw:max-w-full tw:min-h-fit"
    :class="{
      'tw:p-4':
        slotLayout !== 'default' &&
        slotLayout !== 'inline' &&
        slotLayout !== 'full',
    }"
  >
    <Transition
      enter-active-class="tw:transition-opacity tw:duration-200 tw:ease-in-out"
      leave-active-class="tw:transition-opacity tw:duration-200 tw:ease-in-out"
      enter-from-class="tw:opacity-0"
      leave-to-class="tw:opacity-0"
      mode="out-in"
      appear
    >
      <v-row
        :key="gridKey"
        :no-gutters="slotLayout === 'default' || slotLayout === 'full'"
        class="tw:max-w-full tw:self-start"
        :class="{ 'tw:h-full': slotLayout === 'full' }"
      >
        <v-col
          v-for="(column, colIndex) in props.widgetsLayout"
          :key="colIndex"
          :cols="getGridCols(props.widgetsLayout.length)"
          :class="{ 'tw:h-full': slotLayout === 'full' }"
        >
          <v-row
            :no-gutters="slotLayout === 'default' || slotLayout === 'full'"
            :class="[{ 'tw:h-full': slotLayout === 'full' }, rowClasses]"
          >
            <TransitionGroup
              name="grid-item"
              tag="div"
              class="tw:w-full tw:flex tw:flex-wrap"
              appear
            >
              <v-col
                v-for="(slot, slotIndex) in column"
                :key="`${gridKey}-${colIndex}-${slotIndex}`"
                :cols="getSlotCols(slot)"
                :style="{
                  'transition-delay': `${slotIndex * 50}ms`,
                  ...(slotLayout === 'default' || slotLayout === 'full'
                    ? { padding: '0px' }
                    : {}),
                }"
              >
                <div :class="widgetContainerClasses" class="tw:h-full">
                  <component
                    v-if="slot.widget"
                    :is="getSlotWidget(slot.widget)"
                    :uuid="slot.widget.uuid"
                    :class="[
                      hasSpacing &&
                      widgetStates[slot.widget.uuid].config
                        ?.allowPaddingOverride
                        ? 'tw:p-4'
                        : '',
                    ]"
                    v-bind="{
                      ...widgetStates[slot.widget.uuid].config,
                      ...widgetStates[slot.widget.uuid].public,
                      ...routeParams,
                      compositionName: currentRouteConfig?.slotValue,
                      slotType,
                    }"
                  />
                </div>
              </v-col>
            </TransitionGroup>
          </v-row>
        </v-col>
      </v-row>
    </Transition>
  </div>
</template>

<script setup lang="ts">
import type { Composition } from "@shared/types/core/Composition.types"
import type { WidgetBase } from "@racletteCore/store/types"
import {
  watch,
  ref,
  h,
  computed,
  onUnmounted,
  nextTick,
  type Component,
} from "vue"
import { widgetLoader } from "@racletteOrchestrator/helpers/widgetLoader"
import { useDisplay } from "vuetify"
import useStateSubscriber from "@racletteOrchestrator/composables/useStateSubscriber"
import useRouteState from "@racletteOrchestrator/composables/useRouteState"
import { createWidgetLifecycleManager } from "@racletteOrchestrator/composables/useWidgetLifecycle"
import { isDefined } from "@vueuse/core"

const props = withDefaults(
  defineProps<{
    widgetsLayout: Composition["widgetsLayout"]
    slotType: string
    slotLayout: string
  }>(),
  {},
)

const { compositionSlots } = useRouteState()

const currentRouteConfig = computed(() =>
  compositionSlots.value?.find((slot) => slot.slotName === props.slotType),
)

const widgetContainerClasses = computed(() => {
  const baseClasses = "tw:h-auto tw:overflow-visible"

  switch (props.slotLayout) {
    case "spaced":
      return `${baseClasses} tw:rounded-lg`
    case "card":
      return `${baseClasses} tw:rounded-lg tw:shadow-lg hover:tw:shadow-xl tw:transition-shadow tw:duration-200`
    case "border":
      return `${baseClasses} tw:rounded-lg tw:border tw:border-gray-300 tw:dark:border-gray-700`
    default:
      return baseClasses
  }
})

const hasSpacing = computed(() =>
  ["spaced", "card", "border"].includes(props.slotLayout),
)

const rowClasses = computed(() => {
  return hasSpacing.value ? "tw:gap-2" : ""
})

const { mdAndDown } = useDisplay()

const { state: widgetStates } = useStateSubscriber("widgets")
const routeParams = computed(() => {
  const cleanedParams = {}
  if (currentRouteConfig.value?.slotParams) {
    for (const [key, value] of Object.entries(
      currentRouteConfig.value.slotParams,
    )) {
      if (isDefined(value) && value !== "undefined") {
        cleanedParams[key] = value
      }
    }
  }

  return cleanedParams
})

// Create a reactive key that changes when widgetsLayout changes
const gridKey = ref(0)

// Calculate total number of widgets
const totalWidgets = computed(() => {
  return props.widgetsLayout.reduce((sum, column) => sum + column.length, 0)
})

// Widget lifecycle manager
const lifecycleManager = ref(createWidgetLifecycleManager(totalWidgets.value))

// Widget component cache
const widgetComponentCache = new Map<string, Component>()

const getSlotWidget = (widget: WidgetBase) => {
  const cacheKey = `${widget.pluginKey}-${widget.name}-${widget.uuid}`

  if (!widgetComponentCache.has(cacheKey)) {
    try {
      const originalComponent = widgetLoader(widget)

      // Wrap the component to inject lifecycle hooks
      const wrappedComponent = {
        name: `${originalComponent.name || "Widget"}Wrapper`,
        setup(props, context) {
          const { onAllWidgetsReady, onWidgetRendered, onWidgetUnmounted } =
            lifecycleManager.value.createLifecycleHooks(widget.uuid)

          onUnmounted(() => {
            onWidgetUnmounted()
          })

          // Pass lifecycle hook to the component as a prop
          const enhancedProps = {
            ...props,
            onAllWidgetsReady,
            ref: (el: any) => {
              if (el) {
                // Element is mounted, observe it
                nextTick(() => {
                  // Get the actual DOM element
                  const element = el.$el || el
                  if (element instanceof HTMLElement) {
                    onWidgetRendered(element)
                  }
                })
              }
            },
          }

          return () => h(originalComponent, enhancedProps, context.slots)
        },
      }

      widgetComponentCache.set(cacheKey, wrappedComponent)
    } catch (error) {
      console.error("🚨 Error creating widget component:", error)
      // Cache error component too
      widgetComponentCache.set(cacheKey, {
        name: "ComponentCreationError",
        setup() {
          return () =>
            h(
              "div",
              { class: "p-4 text-red-500 border border-red-300 rounded" },
              "Error creating component",
            )
        },
      })
    }
  }

  return widgetComponentCache.get(cacheKey)
}

const getGridCols = (rowLength) => (mdAndDown.value ? 12 : 12 / rowLength)

const getSlotCols = (slot) => (mdAndDown.value ? 12 : slot.column)

// Watch for changes in widgetsLayout to trigger transition and reset lifecycle
watch(
  () => props.widgetsLayout,
  () => {
    // Reset lifecycle manager
    lifecycleManager.value.reset()

    // Clear component cache to force re-wrapping with new lifecycle manager
    widgetComponentCache.clear()

    // Create new lifecycle manager with updated widget count
    lifecycleManager.value = createWidgetLifecycleManager(totalWidgets.value)

    // Trigger grid transition
    gridKey.value++
  },
  { deep: true },
)
</script>
