<script lang="ts" setup>
import { computed, reactive, ref, watch } from 'vue';

import { IconifyIcon } from '@vben/icons';

import {
  Button,
  Drawer,
  Empty,
  Form,
  Input,
  InputNumber,
  message,
  Spin,
  Switch,
  Tag,
} from 'antdv-next';

import { listBadgePictureBySysOrigin } from '#/api/legacy/badge';
import { listGiftBySysOrigin } from '#/api/legacy/gift';
import {
  listNotFamilyBySysOriginType,
  saveOrUpdatePropsActivityRewardGroup,
} from '#/api/legacy/props';
import { getResidentVipConfig } from '#/api/legacy/resident-activity';
import { getDisplaySysOriginText } from '#/views/system/shared';

import {
  BADGE_TYPE_OPTIONS,
  formatRewardText,
  getPropsTypeName,
  PROPS_SOURCE_GROUP_TYPE_MAP,
  PROPS_TYPES,
} from '../shared';
import RewardIcon from './reward-icon.vue';

const GROUP_GIFT_TYPE_VALUE = '__GIFT__';
const GROUP_BADGE_TYPE_VALUE = '__BADGE__';
const GROUP_RESOURCE_PAGE_SIZE = 96;

const props = defineProps<{
  open: boolean;
  record: null | Record<string, any>;
  sysOrigin: string;
}>();

const emit = defineEmits<{
  close: [];
  success: [];
}>();

type ResourceKind = 'badge' | 'currency' | 'gift' | 'props' | 'vip';

type TypeOption = {
  icon: string;
  kind: ResourceKind;
  label: string;
  value: string;
};

type DisplayResource = {
  amount?: number | string;
  cover?: string;
  durationDays?: number;
  id: number | string;
  key: string;
  kind: ResourceKind;
  level?: number;
  name: string;
  raw?: Record<string, any>;
  remark?: string;
  sourceUrl?: string;
  type: string;
  typeLabel: string;
};

type RewardGroupItem = {
  amount?: number | string;
  badgeName?: string;
  content: number | string;
  cover?: string;
  detailType: string;
  name?: string;
  quantity: number | string;
  remark: string;
  sourceUrl?: string;
  type: string;
  typeLabel?: string;
};

const saving = ref(false);
const sourceLoading = ref(false);
const resourceKeyword = ref('');
const currentResourcePage = ref(1);
const selectedType = ref('');
const goldAmount = ref<null | number>(null);

const form = reactive<{
  id: number | string;
  name: string;
  rewardConfigList: RewardGroupItem[];
  shelfStatus: boolean;
  sysOrigin: string;
}>({
  id: '',
  name: '',
  rewardConfigList: [],
  shelfStatus: true,
  sysOrigin: '',
});

const sourceOptionsMap = reactive<
  Record<string, { list: DisplayResource[]; loaded: boolean; loading: boolean }>
>({});

const propsTypeOptions = PROPS_TYPES.filter((item) => item.value !== 'CUSTOMIZE');

const typeOptions = computed<TypeOption[]>(() => [
  ...propsTypeOptions.map((item) => ({
    icon: 'lucide:package',
    kind: 'props' as ResourceKind,
    label: item.name,
    value: String(item.value),
  })),
  {
    icon: 'lucide:coins',
    kind: 'currency',
    label: '金币',
    value: 'GOLD',
  },
  {
    icon: 'lucide:award',
    kind: 'badge',
    label: '徽章',
    value: GROUP_BADGE_TYPE_VALUE,
  },
  {
    icon: 'lucide:gift',
    kind: 'gift',
    label: '礼物',
    value: GROUP_GIFT_TYPE_VALUE,
  },
  {
    icon: 'lucide:crown',
    kind: 'vip',
    label: 'VIP',
    value: 'NOBLE_VIP',
  },
]);

const title = computed(() => {
  const sysOrigin = getDisplaySysOriginText(props.sysOrigin || form.sysOrigin);
  const action = form.id ? '修改资源组' : '添加资源组';
  return sysOrigin ? `${action}（${sysOrigin}）` : action;
});

const rewardItems = computed(() => form.rewardConfigList);
const currentTypeOption = computed(
  () => typeOptions.value.find((item) => item.value === selectedType.value) || null,
);
const currentTypeLabel = computed(() => currentTypeOption.value?.label || '请选择类型');
const sourceOptions = computed<DisplayResource[]>(
  () => sourceOptionsMap[selectedType.value]?.list || [],
);
const filteredResources = computed(() => {
  const keyword = resourceKeyword.value.trim().toLowerCase();
  if (!keyword) {
    return sourceOptions.value;
  }
  return sourceOptions.value.filter(
    (item) =>
      String(item.id).toLowerCase().includes(keyword) ||
      item.name.toLowerCase().includes(keyword) ||
      item.typeLabel.toLowerCase().includes(keyword),
  );
});
const pagedResources = computed(() => {
  const start = (currentResourcePage.value - 1) * GROUP_RESOURCE_PAGE_SIZE;
  return filteredResources.value.slice(start, start + GROUP_RESOURCE_PAGE_SIZE);
});
const selectedResourceKeys = computed(
  () => new Set(form.rewardConfigList.map((item) => getRewardKey(item))),
);
const selectedTypeSummary = computed(() => {
  const labels = [
    ...new Set(form.rewardConfigList.map((item) => getItemTypeLabel(item)).filter(Boolean)),
  ];
  return labels.length > 0 ? labels.join('、') : '-';
});

function resetSourceOptionsMap() {
  Object.keys(sourceOptionsMap).forEach((key) => {
    delete sourceOptionsMap[key];
  });
}

function createTypeStore(type: string) {
  if (!sourceOptionsMap[type]) {
    sourceOptionsMap[type] = { list: [], loaded: false, loading: false };
  }
  return sourceOptionsMap[type];
}

function resetForm() {
  form.id = '';
  form.name = '';
  form.rewardConfigList = [];
  form.shelfStatus = true;
  form.sysOrigin = props.sysOrigin || '';
}

function firstPresent(record: Record<string, any>, keys: string[]) {
  for (const key of keys) {
    const value = record?.[key];
    if (value !== undefined && value !== null && String(value).trim() !== '') {
      return value;
    }
  }
  return '';
}

function normalizeDisplayResource(
  item: Record<string, any>,
  kind: ResourceKind,
  detailType: string,
  typeLabel: string,
): DisplayResource {
  let id = firstPresent(item, ['id', 'resourceId', 'propsSourceId', 'propsId']);
  let name = firstPresent(item, ['name', 'resourceName', 'sourceName']);
  if (kind === 'badge') {
    id = firstPresent(item, ['badgeConfigId', 'id', 'badgeId']);
    name = firstPresent(item, ['badgeName', 'name']);
  } else if (kind === 'gift') {
    id = firstPresent(item, ['id', 'giftId']);
    name = firstPresent(item, ['giftName', 'name']);
  }

  const cover = firstPresent(item, [
    'cover',
    'coverUrl',
    'giftPhoto',
    'resourceCover',
    'resourceCoverUrl',
    'selectUrl',
    'icon',
  ]);

  return {
    amount: firstPresent(item, ['amount', 'giftCandy', 'price', 'goldAmount', 'priceGold']),
    cover: String(cover || ''),
    durationDays: Number(firstPresent(item, ['durationDays']) || 0) || undefined,
    id: String(id ?? ''),
    key: getResourceKey(kind, detailType, id),
    kind,
    level: Number(firstPresent(item, ['level']) || 0) || undefined,
    name: String(name || (id ? `资源 ${id}` : '-')),
    raw: item,
    remark: String(firstPresent(item, ['remark', 'displayName']) || ''),
    sourceUrl: String(
      firstPresent(item, ['sourceUrl', 'resourceUrl', 'url', 'giftSourceUrl', 'animationUrl']) ||
        '',
    ),
    type: detailType,
    typeLabel,
  };
}

function normalizeVipResource(value: null | Record<string, any> | undefined) {
  return {
    cover: String(value?.cover || value?.coverUrl || '').trim(),
    sourceUrl: String(
      value?.sourceUrl || value?.resourceUrl || value?.url || value?.cover || '',
    ).trim(),
  };
}

function pickVipPreviewResource(item: Record<string, any>) {
  const fields = [
    'shortBadge',
    'longBadge',
    'avatarFrame',
    'entryEffect',
    'chatBubble',
    'floatPicture',
    'backgroundCard',
    'effectImage',
  ];
  for (const field of fields) {
    const resource = normalizeVipResource(item[field]);
    if (resource.cover || resource.sourceUrl) {
      return resource;
    }
  }
  return { cover: '', sourceUrl: '' };
}

function uniqueResources(list: DisplayResource[]) {
  const map = new Map<string, DisplayResource>();
  list.forEach((item) => {
    if (!map.has(item.key)) {
      map.set(item.key, item);
    }
  });
  return [...map.values()];
}

function getResourceKey(kind: ResourceKind, detailType: string, id: number | string) {
  return `${kind}-${detailType}-${id}`;
}

function getRewardKind(item: RewardGroupItem): ResourceKind {
  if (item.type === 'GOLD') {
    return 'currency';
  }
  if (item.type === 'GIFT') {
    return 'gift';
  }
  if (item.type === 'BADGE') {
    return 'badge';
  }
  if (item.detailType === 'NOBLE_VIP') {
    return 'vip';
  }
  return 'props';
}

function getRewardKey(item: RewardGroupItem) {
  return getResourceKey(getRewardKind(item), item.detailType || item.type, item.content);
}

function formatResourceAmount(value: number | string | undefined) {
  if (value === undefined || value === null || String(value).trim() === '') {
    return '-';
  }
  const numeric = Number(value);
  if (Number.isFinite(numeric)) {
    return numeric.toLocaleString('zh-CN');
  }
  return String(value);
}

function getItemTypeLabel(item: RewardGroupItem) {
  return item.typeLabel || getPropsTypeName(item.detailType || item.type);
}

function getItemName(item: RewardGroupItem) {
  return item.name || item.badgeName || item.remark || String(item.content || '-');
}

function getQuantityLabel(item: RewardGroupItem) {
  if (item.type === 'GOLD') {
    return '金币';
  }
  if (item.type === 'GIFT') {
    return '数量';
  }
  if (item.detailType === 'SPECIAL_ID') {
    return '数量';
  }
  return '天数';
}

function getDefaultQuantity(resource: DisplayResource) {
  if (resource.kind === 'currency') {
    return 0;
  }
  if (resource.kind === 'gift') {
    return 1;
  }
  if (resource.kind === 'vip') {
    return resource.durationDays || 30;
  }
  if (resource.type === 'SPECIAL_ID') {
    return 1;
  }
  return 7;
}

function getRewardType(resource: DisplayResource) {
  if (resource.kind === 'currency') {
    return resource.type;
  }
  if (resource.kind === 'gift') {
    return 'GIFT';
  }
  if (resource.kind === 'badge') {
    return 'BADGE';
  }
  return PROPS_SOURCE_GROUP_TYPE_MAP[resource.type]?.value || 'PROPS';
}

function buildRewardItem(resource: DisplayResource): RewardGroupItem {
  const item: RewardGroupItem = {
    amount: resource.amount,
    content: resource.id,
    cover: resource.cover || resource.sourceUrl || '',
    detailType: resource.type,
    name: resource.name,
    quantity: getDefaultQuantity(resource),
    remark: resource.remark || resource.name || '',
    sourceUrl: resource.sourceUrl || '',
    type: getRewardType(resource),
    typeLabel: resource.typeLabel,
  };
  if (resource.kind === 'badge') {
    item.badgeName = resource.name;
  }
  return item;
}

function applyResourcePreview(item: RewardGroupItem, resource: DisplayResource) {
  if (!String(item.cover || '').trim()) {
    item.cover = resource.cover || resource.sourceUrl || '';
  }
  if (!String(item.sourceUrl || '').trim()) {
    item.sourceUrl = resource.sourceUrl || '';
  }
  if (!String(item.name || '').trim()) {
    item.name = resource.name;
  }
  if (!String(item.remark || '').trim()) {
    item.remark = resource.remark || resource.name || '';
  }
  if (!String(item.typeLabel || '').trim()) {
    item.typeLabel = resource.typeLabel;
  }
  if (
    (item.amount === undefined ||
      item.amount === null ||
      String(item.amount).trim() === '') &&
    resource.amount !== undefined
  ) {
    item.amount = resource.amount;
  }
}

function hydrateSelectedItemsFromResources(resources: DisplayResource[]) {
  if (resources.length === 0 || form.rewardConfigList.length === 0) {
    return;
  }
  const resourceMap = new Map(resources.map((item) => [item.key, item]));
  form.rewardConfigList.forEach((item) => {
    const resource = resourceMap.get(getRewardKey(item));
    if (resource) {
      applyResourcePreview(item, resource);
    }
  });
}

function selectType(option: TypeOption) {
  if (selectedType.value === option.value) {
    return;
  }
  selectedType.value = option.value;
  resourceKeyword.value = '';
  currentResourcePage.value = 1;
  goldAmount.value = null;
  void loadOptions(option.value);
}

async function loadOptions(type: string) {
  if (!type || !form.sysOrigin) {
    return;
  }
  if (type === 'GOLD') {
    return;
  }
  const store = createTypeStore(type);
  if (store.loaded || store.loading) {
    return;
  }
  store.loading = true;
  sourceLoading.value = true;
  try {
    if (type === GROUP_BADGE_TYPE_VALUE) {
      const results = await Promise.all(
        BADGE_TYPE_OPTIONS.map(async (badgeType) => {
          const rows = await listBadgePictureBySysOrigin(
            form.sysOrigin,
            String(badgeType.value),
          );
          return (rows || []).map((item) =>
            normalizeDisplayResource(
              item,
              'badge',
              String(badgeType.value),
              badgeType.name,
            ),
          );
        }),
      );
      store.list = uniqueResources(results.flat());
      hydrateSelectedItemsFromResources(store.list);
      store.loaded = true;
      return;
    }

    if (type === GROUP_GIFT_TYPE_VALUE) {
      const rows = await listGiftBySysOrigin(form.sysOrigin);
      store.list = (rows || []).map((item) =>
        normalizeDisplayResource(item, 'gift', 'GIFT', '礼物'),
      );
      hydrateSelectedItemsFromResources(store.list);
      store.loaded = true;
      return;
    }

    if (type === 'NOBLE_VIP') {
      const config = await getResidentVipConfig(form.sysOrigin);
      const levels = Array.isArray(config?.levels) ? config.levels : [];
      store.list = levels
        .filter((item: Record<string, any>) => item.enabled && item.id)
        .map((item: Record<string, any>) => {
          const preview = pickVipPreviewResource(item);
          const durationDays = Number(item.durationDays || 30);
          const level = Number(item.level || 0);
          return normalizeDisplayResource(
            {
              cover: preview.cover,
              durationDays,
              id: String(item.id ?? ''),
              level,
              name: String(item.displayName || item.levelCode || `VIP ${level}`),
              priceGold: Number(item.priceGold || 0),
              remark: `${durationDays} 天`,
              sourceUrl: preview.sourceUrl,
            },
            'vip',
            'NOBLE_VIP',
            'VIP',
          );
        });
      hydrateSelectedItemsFromResources(store.list);
      store.loaded = true;
      return;
    }

    const typeLabel = getPropsTypeName(type);
    const rows = await listNotFamilyBySysOriginType(form.sysOrigin, type);
    store.list = (rows || []).map((item) =>
      normalizeDisplayResource(item, 'props', type, typeLabel),
    );
    hydrateSelectedItemsFromResources(store.list);
    store.loaded = true;
  } finally {
    store.loading = false;
    sourceLoading.value = false;
  }
}

function toggleResource(resource: DisplayResource) {
  const index = form.rewardConfigList.findIndex(
    (item) => getRewardKey(item) === resource.key,
  );
  if (index !== -1) {
    form.rewardConfigList.splice(index, 1);
    return;
  }
  form.rewardConfigList.push(buildRewardItem(resource));
}

function addGoldItem() {
  const amount = Number(goldAmount.value);
  if (!Number.isFinite(amount) || amount <= 0) {
    message.warning('请输入金币数量');
    return;
  }
  const item: RewardGroupItem = {
    amount,
    content: amount,
    detailType: 'GOLD',
    name: '金币',
    quantity: 0,
    remark: '金币',
    type: 'GOLD',
    typeLabel: '金币',
  };
  const index = form.rewardConfigList.findIndex(
    (reward) => reward.type === 'GOLD' && reward.detailType === 'GOLD',
  );
  if (index !== -1) {
    form.rewardConfigList[index] = item;
  } else {
    form.rewardConfigList.push(item);
  }
  goldAmount.value = null;
}

function removeItem(index: number) {
  form.rewardConfigList.splice(index, 1);
}

function clearItems() {
  form.rewardConfigList = [];
}

function moveItem(index: number, direction: -1 | 1) {
  const target = index + direction;
  if (target < 0 || target >= form.rewardConfigList.length) {
    return;
  }
  const list = [...form.rewardConfigList];
  const current = list[index];
  const next = list[target];
  if (!current || !next) {
    return;
  }
  list[index] = next;
  list[target] = current;
  form.rewardConfigList = list;
}

function updateItemQuantity(index: number, value: number | string | null) {
  const item = form.rewardConfigList[index];
  if (!item) {
    return;
  }
  if (item.type === 'GOLD') {
    item.content = value ?? 0;
    item.amount = value ?? 0;
    return;
  }
  item.quantity = value ?? 0;
}

function getItemInputValue(item: RewardGroupItem) {
  if (item.type === 'GOLD') {
    return Number(item.content || 0);
  }
  return Number(item.quantity || 0);
}

function validateItems() {
  for (const item of form.rewardConfigList) {
    const quantity = Number(item.quantity);
    if (item.quantity === '' || !Number.isFinite(quantity)) {
      message.warning(`${getItemName(item)} 的${getQuantityLabel(item)}不能为空`);
      return false;
    }
    if (item.type === 'GOLD') {
      const amount = Number(item.content);
      if (!Number.isFinite(amount) || amount <= 0) {
        message.warning('金币数量必须大于 0');
        return false;
      }
      continue;
    }
    if (item.type === 'GIFT' && quantity <= 0) {
      message.warning(`${getItemName(item)} 的数量必须大于 0`);
      return false;
    }
  }
  return true;
}

async function handleSubmit() {
  if (!String(form.name || '').trim()) {
    message.warning('请输入类型名称');
    return;
  }
  if (form.rewardConfigList.length === 0) {
    message.warning('请先配置资源组内容');
    return;
  }
  if (!validateItems()) {
    return;
  }
  saving.value = true;
  try {
    await saveOrUpdatePropsActivityRewardGroup({
      id: form.id || undefined,
      name: form.name.trim(),
      rewardConfigList: form.rewardConfigList.map(
        (item: RewardGroupItem, index: number) => ({
          content: item.content,
          detailType: item.detailType,
          quantity: Number(item.quantity || 0),
          remark: item.remark,
          sort: index + 1,
          type: item.type,
        }),
      ),
      shelfStatus: form.shelfStatus,
      sysOrigin: form.sysOrigin,
    });
    message.success('保存成功');
    emit('success');
    emit('close');
  } finally {
    saving.value = false;
  }
}

function initDefaultType() {
  const first = typeOptions.value[0]?.value || '';
  selectedType.value = first;
  resourceKeyword.value = '';
  currentResourcePage.value = 1;
  if (first) {
    void loadOptions(first);
  }
}

watch(
  () => props.open,
  (open) => {
    if (!open) {
      return;
    }
    resetSourceOptionsMap();
    const record = props.record;
    if (!record) {
      resetForm();
    } else {
      form.id = record.id ?? '';
      form.name = record.name ?? '';
      form.rewardConfigList = (record.rewardConfigList || []).map(
        (item: RewardGroupItem) => ({
          ...item,
          amount: item.amount,
          name: item.name || item.badgeName || item.remark || '',
          typeLabel: item.typeLabel || getPropsTypeName(item.detailType || item.type),
        }),
      );
      form.shelfStatus = Boolean(record.shelfStatus ?? true);
      form.sysOrigin = props.sysOrigin || record.sysOrigin || '';
    }
    initDefaultType();
  },
  { immediate: true },
);

watch(
  () => props.sysOrigin,
  (value) => {
    if (value) {
      if (form.sysOrigin && form.sysOrigin !== value) {
        resetSourceOptionsMap();
      }
      form.sysOrigin = value;
      if (props.open && selectedType.value) {
        void loadOptions(selectedType.value);
      }
    }
  },
  { immediate: true },
);

watch(resourceKeyword, () => {
  currentResourcePage.value = 1;
});

watch(filteredResources, () => {
  const pageCount = Math.max(
    1,
    Math.ceil(filteredResources.value.length / GROUP_RESOURCE_PAGE_SIZE),
  );
  if (currentResourcePage.value > pageCount) {
    currentResourcePage.value = pageCount;
  }
});
</script>

<template>
  <Drawer
    :open="open"
    :title="title"
    class="source-group-drawer"
    width="1180"
    @close="emit('close')"
  >
    <Form class="group-form" layout="vertical">
      <section class="group-config">
        <div class="group-config__field group-config__field--name">
          <span class="field-label">类型名称</span>
          <Input
            v-model:value="form.name"
            allow-clear
            placeholder="输入资源组名称"
          />
        </div>
        <div class="group-config__field group-config__field--switch">
          <span class="field-label">状态</span>
          <Switch
            v-model:checked="form.shelfStatus"
            checked-children="上架"
            un-checked-children="下架"
          />
        </div>
        <Tag color="blue">已选 {{ rewardItems.length }}</Tag>
      </section>

      <div class="group-layout">
        <section class="group-main">
          <div class="type-tags">
            <button
              v-for="option in typeOptions"
              :key="option.value"
              :class="{ 'type-tag--active': selectedType === option.value }"
              class="type-tag"
              type="button"
              @click="selectType(option)"
            >
              <IconifyIcon :icon="option.icon" />
              <span>{{ option.label }}</span>
            </button>
          </div>

          <div v-if="selectedType === 'GOLD'" class="gold-editor">
            <div class="gold-editor__title">添加金币</div>
            <div class="gold-editor__row">
              <InputNumber
                v-model:value="goldAmount"
                :controls="false"
                :min="1"
                :precision="0"
                class="gold-editor__input"
                placeholder="输入金币数量"
              />
              <Button type="primary" @click="addGoldItem">加入资源组</Button>
            </div>
          </div>

          <div v-else class="resource-section">
            <div class="resource-head">
              <div class="field-head">
                <span>资源列表</span>
                <small>
                  当前 {{ currentTypeLabel }}，共 {{ filteredResources.length }} 个
                </small>
              </div>
              <Input
                v-model:value="resourceKeyword"
                allow-clear
                class="resource-search"
                placeholder="搜索资源名称 / ID"
              />
            </div>

            <Spin :spinning="sourceLoading">
              <div v-if="pagedResources.length > 0" class="resource-grid">
                <button
                  v-for="resource in pagedResources"
                  :key="resource.key"
                  :class="{
                    'resource-icon-card--active':
                      selectedResourceKeys.has(resource.key),
                  }"
                  class="resource-icon-card"
                  type="button"
                  @click="toggleResource(resource)"
                >
                  <span
                    v-if="selectedResourceKeys.has(resource.key)"
                    class="resource-icon-card__check"
                  >
                    <IconifyIcon icon="lucide:check" />
                  </span>
                  <RewardIcon :item="resource" :size="42" />
                  <span class="resource-icon-card__name">{{ resource.name }}</span>
                  <span class="resource-icon-card__type">{{ resource.typeLabel }}</span>
                  <span class="resource-icon-card__price">
                    价格 {{ formatResourceAmount(resource.amount) }}
                  </span>
                </button>
              </div>
              <Empty
                v-else
                :description="selectedType ? '暂无可选资源' : '请选择类型'"
                class="resource-empty"
              />
            </Spin>

            <div
              v-if="filteredResources.length > GROUP_RESOURCE_PAGE_SIZE"
              class="resource-more"
            >
              <Button
                :disabled="
                  currentResourcePage * GROUP_RESOURCE_PAGE_SIZE >=
                  filteredResources.length
                "
                size="small"
                @click="currentResourcePage += 1"
              >
                加载更多
              </Button>
            </div>
          </div>
        </section>

        <aside class="group-summary">
          <div class="summary-title">
            <IconifyIcon icon="lucide:package-check" />
            <span>资源组内容</span>
          </div>

          <div class="selected-panel">
            <div class="selected-panel__head">
              <span>已选资源</span>
              <div class="selected-panel__actions">
                <Tag color="blue">{{ rewardItems.length }}</Tag>
                <button
                  v-if="rewardItems.length > 0"
                  class="selected-clear"
                  type="button"
                  @click="clearItems"
                >
                  清空
                </button>
              </div>
            </div>

            <div v-if="rewardItems.length > 0" class="selected-list">
              <div
                v-for="(item, index) in rewardItems"
                :key="`${item.type}-${item.detailType}-${item.content}-${index}`"
                class="selected-item"
              >
                <div class="selected-item__order">{{ Number(index) + 1 }}</div>
                <RewardIcon :item="item" :size="38" />
                <div class="selected-item__body">
                  <strong>{{ getItemName(item) }}</strong>
                  <span>
                    {{ getItemTypeLabel(item) }} · 价格
                    {{ formatResourceAmount(item.amount) }}
                  </span>
                  <span>{{ formatRewardText(item) }}</span>
                </div>
                <div class="selected-item__qty">
                  <label>{{ getQuantityLabel(item) }}</label>
                  <InputNumber
                    :controls="false"
                    :precision="0"
                    :value="getItemInputValue(item)"
                    class="quantity-input"
                    @change="(value: number | string | null) => updateItemQuantity(Number(index), value)"
                  />
                </div>
                <div class="selected-item__actions">
                  <button
                    aria-label="上移"
                    class="icon-action"
                    type="button"
                    @click="moveItem(Number(index), -1)"
                  >
                    <IconifyIcon icon="lucide:arrow-up" />
                  </button>
                  <button
                    aria-label="下移"
                    class="icon-action"
                    type="button"
                    @click="moveItem(Number(index), 1)"
                  >
                    <IconifyIcon icon="lucide:arrow-down" />
                  </button>
                  <button
                    aria-label="删除"
                    class="icon-action icon-action--danger"
                    type="button"
                    @click="removeItem(Number(index))"
                  >
                    <IconifyIcon icon="lucide:x" />
                  </button>
                </div>
              </div>
            </div>
            <div v-else class="summary-empty">未选择资源</div>
          </div>

          <dl class="summary-list">
            <div>
              <dt>资源数量</dt>
              <dd>{{ rewardItems.length }}</dd>
            </div>
            <div>
              <dt>资源类型</dt>
              <dd>{{ selectedTypeSummary }}</dd>
            </div>
            <div>
              <dt>状态</dt>
              <dd>{{ form.shelfStatus ? '上架' : '下架' }}</dd>
            </div>
          </dl>
        </aside>
      </div>
    </Form>

    <template #footer>
      <div class="drawer-footer">
        <Button @click="emit('close')">取消</Button>
        <Button :loading="saving" type="primary" @click="handleSubmit">
          保存
        </Button>
      </div>
    </template>
  </Drawer>
</template>

<style scoped>
.group-form {
  display: grid;
  gap: 12px;
}

.group-config {
  align-items: center;
  background: #fbfcfe;
  border: 1px solid #edf0f3;
  border-radius: 8px;
  display: grid;
  gap: 10px;
  grid-template-columns: minmax(280px, 1fr) auto auto;
  padding: 10px 12px;
}

.group-config__field {
  align-items: center;
  display: grid;
  gap: 8px;
}

.group-config__field--name {
  grid-template-columns: 64px minmax(0, 1fr);
}

.group-config__field--switch {
  grid-template-columns: 38px auto;
}

.field-label {
  color: #111827;
  font-weight: 600;
  white-space: nowrap;
}

.group-layout {
  align-items: start;
  display: grid;
  gap: 12px;
  grid-template-columns: minmax(0, 1fr) 360px;
}

.group-main,
.group-summary {
  background: #fff;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
}

.group-main {
  display: grid;
  gap: 10px;
  padding: 12px;
}

.type-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.type-tag {
  align-items: center;
  background: #fff;
  border: 1px solid #d9dfe8;
  border-radius: 999px;
  color: #374151;
  cursor: pointer;
  display: inline-flex;
  font-size: 13px;
  gap: 6px;
  line-height: 1;
  min-height: 30px;
  padding: 7px 10px;
  transition:
    background 0.18s ease,
    border-color 0.18s ease,
    color 0.18s ease,
    box-shadow 0.18s ease;
}

.type-tag:hover,
.type-tag--active {
  background: #e8f2ff;
  border-color: #1677ff;
  color: #0958d9;
  box-shadow: 0 6px 14px rgb(22 119 255 / 10%);
}

.resource-section {
  display: grid;
  gap: 8px;
}

.gold-editor {
  align-content: start;
  background: #fbfcfe;
  border: 1px solid #edf0f3;
  border-radius: 8px;
  display: grid;
  gap: 10px;
  min-height: 420px;
  padding: 14px;
}

.gold-editor__title {
  color: #111827;
  font-size: 15px;
  font-weight: 700;
}

.gold-editor__row {
  align-items: center;
  display: grid;
  gap: 8px;
  grid-template-columns: minmax(240px, 360px) auto;
  justify-content: start;
}

.gold-editor__input {
  width: 100%;
}

.field-head,
.resource-head,
.selected-panel__head {
  align-items: center;
  color: #111827;
  display: flex;
  font-weight: 600;
  justify-content: space-between;
}

.field-head small,
.resource-head small {
  color: #6b7280;
  font-size: 12px;
  font-weight: 400;
  margin-left: 8px;
}

.resource-head {
  gap: 12px;
}

.resource-search {
  max-width: 300px;
}

.resource-grid {
  align-content: start;
  align-items: start;
  border: 1px solid #edf0f3;
  border-radius: 8px;
  display: grid;
  gap: 8px;
  grid-auto-rows: 112px;
  grid-template-columns: repeat(auto-fill, minmax(116px, 1fr));
  max-height: calc(100vh - 282px);
  min-height: 420px;
  overflow: auto;
  padding: 8px;
}

.resource-icon-card {
  align-items: center;
  background: #fff;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  cursor: pointer;
  display: grid;
  gap: 4px;
  height: 112px;
  justify-items: center;
  min-height: 112px;
  min-width: 0;
  overflow: hidden;
  padding: 8px 6px;
  position: relative;
  text-align: center;
  transition:
    background 0.18s ease,
    border-color 0.18s ease,
    box-shadow 0.18s ease;
}

.resource-icon-card:hover,
.resource-icon-card--active {
  border-color: #1677ff;
  box-shadow: 0 0 0 1px #1677ff inset;
}

.resource-icon-card--active {
  background: #eef6ff;
}

.resource-icon-card__check {
  align-items: center;
  background: #1677ff;
  border-radius: 999px;
  color: #fff;
  display: inline-flex;
  height: 20px;
  justify-content: center;
  position: absolute;
  right: 6px;
  top: 6px;
  width: 20px;
}

.resource-icon-card__name,
.resource-icon-card__type,
.resource-icon-card__price {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.resource-icon-card__name {
  color: #111827;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.25;
}

.resource-icon-card__type {
  color: #6b7280;
  font-size: 11px;
  line-height: 1.15;
}

.resource-icon-card__price {
  background: #fff7e6;
  border-radius: 999px;
  color: #8c5a00;
  font-size: 11px;
  line-height: 1.25;
  padding: 2px 7px;
}

.resource-empty {
  border: 1px dashed #d1d5db;
  border-radius: 8px;
  padding: 54px 0;
}

.resource-more {
  display: flex;
  justify-content: center;
}

.group-summary {
  align-self: start;
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-height: calc(100vh - 126px);
  overflow: hidden;
  padding: 12px;
  position: sticky;
  top: 0;
}

.summary-title {
  align-items: center;
  color: #111827;
  display: flex;
  font-size: 16px;
  font-weight: 700;
  gap: 8px;
}

.summary-title svg {
  color: #1677ff;
}

.selected-panel {
  background: #f9fafb;
  border: 1px solid #edf0f3;
  border-radius: 8px;
  display: grid;
  gap: 8px;
  min-height: 0;
  padding: 10px;
}

.selected-panel__actions {
  align-items: center;
  display: inline-flex;
  gap: 6px;
}

.selected-clear {
  background: transparent;
  border: 0;
  color: #1677ff;
  cursor: pointer;
  font-size: 12px;
  padding: 0;
}

.selected-list {
  display: grid;
  gap: 6px;
  max-height: min(58vh, 560px);
  overflow: auto;
}

.selected-item {
  align-items: center;
  background: #fff;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  display: grid;
  gap: 8px;
  grid-template-columns: 22px auto minmax(0, 1fr) 74px auto;
  min-height: 66px;
  padding: 6px;
}

.selected-item__order {
  align-items: center;
  background: #f1f5f9;
  border-radius: 999px;
  color: #475569;
  display: inline-flex;
  font-size: 11px;
  font-weight: 700;
  height: 22px;
  justify-content: center;
  width: 22px;
}

.selected-item__body {
  min-width: 0;
}

.selected-item__body strong,
.selected-item__body span {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.selected-item__body strong {
  color: #111827;
  font-size: 13px;
  line-height: 1.2;
}

.selected-item__body span {
  color: #6b7280;
  font-size: 11px;
  line-height: 1.35;
}

.selected-item__qty {
  display: grid;
  gap: 3px;
}

.selected-item__qty label {
  color: #6b7280;
  font-size: 11px;
  line-height: 1;
}

.quantity-input {
  width: 68px;
}

.quantity-input :deep(input) {
  text-align: center;
}

.selected-item__actions {
  display: grid;
  gap: 2px;
}

.icon-action {
  align-items: center;
  background: transparent;
  border: 0;
  color: #6b7280;
  cursor: pointer;
  display: inline-flex;
  height: 22px;
  justify-content: center;
  padding: 0;
  width: 22px;
}

.icon-action:hover {
  color: #1677ff;
}

.icon-action--danger:hover {
  color: #d4380d;
}

.summary-empty {
  align-items: center;
  color: #6b7280;
  display: flex;
  justify-content: center;
  min-height: 80px;
}

.summary-list {
  display: grid;
  gap: 0;
  margin: 0;
}

.summary-list div {
  align-items: center;
  border-top: 1px solid #f0f2f5;
  display: flex;
  justify-content: space-between;
  min-height: 32px;
}

.summary-list dt {
  color: #6b7280;
}

.summary-list dd {
  color: #111827;
  font-weight: 600;
  margin: 0;
  max-width: 220px;
  overflow: hidden;
  text-align: right;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.drawer-footer {
  align-items: center;
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}

@media (max-width: 1120px) {
  .group-config,
  .group-layout {
    grid-template-columns: 1fr;
  }

  .group-summary {
    position: static;
  }
}
</style>
