<script setup lang="ts">
/**
 * Props-driven `tab-list` composition — renders the shadcn-vue Tabs
 * primitive where each panel is a nested DisplayCard rendered via
 * `CardRenderer`. Each tab is a fully-resolved DisplayCard (not an ID
 * lookup).
 *
 * Self-contained — directly mountable in any Vue app:
 *
 *   <TabListCard
 *     v-model="activeTab"
 *     :tabs="[generalCard, advancedCard]"
 *     :item="dataModel"
 *   />
 *
 * The tab label comes from the child card's `title`, falling back to
 * the card's `id`. The first child is the default active tab.
 */
import { computed, ref, watch } from "vue"
import type { DisplayCard } from "@/definitions/cards"
import type { TabListCardStyle } from "@/definitions/cards/TabListCard"
import CardRenderer from "@/engine/CardRenderer.vue"
import {
  Tabs,
  TabsContent,
  TabsList,
  TabsTrigger,
} from "@/components/ui/tabs"

export interface TabListCardProps {
  title?: string
  subtitle?: string
  showCard?: boolean
  /** Resolved tab cards (NOT IDs). */
  tabs?: DisplayCard[]
  /** Page-level data model passed through to child renderers. */
  item?: Record<string, unknown>
  /** Initial active tab id. Falls back to the first tab. */
  defaultTab?: string
  /** Vertical or horizontal nav layout. */
  style?: TabListCardStyle
  /** Force the nav bar to render above the panel content. */
  navOnTop?: boolean
  /** Hide the nav bar entirely (used when an external nav controls the tabs). */
  hideNav?: boolean
}

const props = withDefaults(defineProps<TabListCardProps>(), {
  tabs: () => [],
  item: () => ({}),
  style: "default",
  navOnTop: false,
  hideNav: false,
})

const activeTab = defineModel<string>("modelValue")

const tabList = computed<DisplayCard[]>(() => props.tabs ?? [])

const tabIds = computed<string[]>(() => tabList.value.map((t) => t.id))

function labelFor(card: DisplayCard): string {
  if (card.title) {
    return card.title
  }
  return card.id
}

const internalActive = ref<string>(
  activeTab.value ?? props.defaultTab ?? tabIds.value[0] ?? "",
)

watch(
  () => activeTab.value,
  (next) => {
    if (next !== undefined && next !== internalActive.value) {
      internalActive.value = next
    }
  },
)

watch(
  () => tabIds.value,
  (next) => {
    if (!next.includes(internalActive.value)) {
      internalActive.value = next[0] ?? ""
      if (activeTab.value !== internalActive.value) {
        activeTab.value = internalActive.value
      }
    }
  },
)

function onTabChange(value: string | number): void {
  const id = String(value)
  internalActive.value = id
  activeTab.value = id
}

const navOnTopComputed = computed<boolean>(
  () => props.style === "horizontal" || props.navOnTop === true,
)

const wrapperClass = computed(() => [
  "gxp-tab-list",
  navOnTopComputed.value ? "flex flex-col gap-3" : "flex flex-row gap-3",
])
</script>

<template>
  <header v-if="title || subtitle" class="mb-3 flex flex-col gap-0.5">
    <h3 v-if="title" class="text-base font-semibold">{{ title }}</h3>
    <p v-if="subtitle" class="text-sm text-muted-foreground">
      {{ subtitle }}
    </p>
  </header>
  <Tabs
    v-if="tabList.length > 0"
    :model-value="internalActive"
    :default-value="defaultTab ?? tabIds[0]"
    :class="wrapperClass"
    :orientation="navOnTopComputed ? 'horizontal' : 'vertical'"
    @update:model-value="onTabChange"
  >
    <TabsList
      v-if="!hideNav"
      :class="[
        'inline-flex items-center rounded-md bg-muted p-1',
        navOnTopComputed ? 'flex-row' : 'flex-col h-auto',
      ]"
    >
      <TabsTrigger
        v-for="tab in tabList"
        :key="tab.id"
        :value="tab.id"
        :data-tab-id="tab.id"
        class="rounded-sm px-3 py-1.5 text-sm font-medium data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm"
      >
        {{ labelFor(tab) }}
      </TabsTrigger>
    </TabsList>
    <div class="flex-1">
      <TabsContent
        v-for="tab in tabList"
        :key="tab.id"
        :value="tab.id"
        :data-tab-panel-id="tab.id"
      >
        <CardRenderer :card="tab" :item="item" />
      </TabsContent>
    </div>
  </Tabs>
  <p
    v-else
    class="text-sm text-muted-foreground italic"
    data-testid="tab-list-empty"
  >
    No tabs to display.
  </p>
</template>
