<!-- SPEC: PJ2026-010405 云端控制台. -->
<!-- Implementation reference: draft-2026-07-13-p0-cloud-console. -->
<!-- Responsibility: 以 list/listitem 语义承载同一资源合同的卡片与列表视图。 -->

<script setup lang="ts" generic="T extends object">
import type { Component } from "vue";
import { Grid2X2, List, Rows3, Rows4 } from "lucide-vue-next";
import EntityCard from "./EntityCard.vue";
import VirtualList from "./VirtualList.vue";
import ViewModeSwitch from "@/components/console/ViewModeSwitch.vue";

const viewOptions = [
  { value: "cards", label: "卡片", icon: Grid2X2 },
  { value: "list", label: "列表", icon: List }
];
const densityOptions = [
  { value: "comfortable", label: "舒适密度", icon: Rows4 },
  { value: "compact", label: "紧凑密度", icon: Rows3 }
];

withDefaults(defineProps<{
  items: T[];
  itemKey: (item: T) => string;
  itemTitle?: (item: T) => string;
  itemSubtitle?: (item: T) => string;
  itemStatus?: (item: T) => string;
  itemIcon?: (item: T) => Component;
  view?: "cards" | "list";
  density?: "compact" | "comfortable";
  selectedId?: string | null;
  ariaLabel?: string;
  emptyText?: string;
  showControls?: boolean;
  virtualizeAfter?: number;
  virtualItemHeight?: number;
  virtualHeight?: number | string;
}>(), {
  itemTitle: undefined,
  itemSubtitle: undefined,
  itemStatus: undefined,
  itemIcon: undefined,
  view: "cards",
  density: "comfortable",
  selectedId: null,
  ariaLabel: "资源集合",
  emptyText: "暂无资源。",
  showControls: true,
  virtualizeAfter: 80,
  virtualItemHeight: 56,
  virtualHeight: "min(62vh, 680px)"
});

const emitEvent = defineEmits<{
  select: [item: T];
  "update:view": [view: "cards" | "list"];
  "update:density": [density: "compact" | "comfortable"];
}>();

function selectItem(item: T): void {
  emitEvent("select", item);
}
</script>

<template>
  <section class="resource-collection" :aria-label="ariaLabel">
    <header v-if="showControls || $slots.toolbar" class="resource-collection-toolbar">
      <slot name="toolbar"><span class="resource-collection-count">{{ items.length }} items</span></slot>
      <div v-if="showControls" class="page-command-actions">
        <ViewModeSwitch :model-value="view" :options="viewOptions" label="显示模式" @update:model-value="emitEvent('update:view', $event as 'cards' | 'list')" />
        <ViewModeSwitch :model-value="density" :options="densityOptions" label="显示密度" @update:model-value="emitEvent('update:density', $event as 'compact' | 'comfortable')" />
      </div>
    </header>
    <VirtualList
      v-if="items.length >= virtualizeAfter && view === 'list'"
      class="resource-collection-virtual"
      :items="items"
      :item-key="itemKey"
      :item-height="virtualItemHeight"
      :height="virtualHeight"
      :aria-label="ariaLabel"
    >
      <template #default="{ item }">
        <div class="resource-collection-item resource-collection-item--virtual">
          <slot
            v-if="$slots.list"
            name="list"
            :item="item"
            :selected="itemKey(item) === selectedId"
            :select="() => selectItem(item)"
          />
          <EntityCard
            v-else
            :title="itemTitle?.(item) || itemKey(item)"
            :subtitle="itemSubtitle?.(item)"
            :status="itemStatus?.(item)"
            :icon="itemIcon?.(item)"
            :selected="itemKey(item) === selectedId"
            @select="selectItem(item)"
          />
        </div>
      </template>
    </VirtualList>
    <div v-else-if="items.length" class="resource-collection-items" :data-view="view" :data-density="density" role="list" :aria-label="ariaLabel">
      <div v-for="item in items" :key="itemKey(item)" class="resource-collection-item" role="listitem">
        <slot
          v-if="view === 'list' && $slots.list"
          name="list"
          :item="item"
          :selected="itemKey(item) === selectedId"
          :select="() => selectItem(item)"
        />
        <EntityCard
          v-else-if="view === 'list'"
          :title="itemTitle?.(item) || itemKey(item)"
          :subtitle="itemSubtitle?.(item)"
          :status="itemStatus?.(item)"
          :icon="itemIcon?.(item)"
          :selected="itemKey(item) === selectedId"
          @select="selectItem(item)"
        />
        <slot
          v-else-if="$slots.card"
          name="card"
          :item="item"
          :selected="itemKey(item) === selectedId"
          :select="() => selectItem(item)"
        />
        <EntityCard
          v-else
          :title="itemTitle?.(item) || itemKey(item)"
          :subtitle="itemSubtitle?.(item)"
          :status="itemStatus?.(item)"
          :icon="itemIcon?.(item)"
          :selected="itemKey(item) === selectedId"
          @select="selectItem(item)"
        />
      </div>
    </div>
    <slot v-else name="empty"><p class="muted-box">{{ emptyText }}</p></slot>
  </section>
</template>
