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

import { Page } from '@vben/common-ui';
import { IconifyIcon } from '@vben/icons';
import { useAccessStore } from '@vben/stores';

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

import { listBadgePictureBySysOrigin } from '#/api/legacy/badge';
import { listGiftBySysOrigin } from '#/api/legacy/gift';
import {
  listNotFamilyBySysOriginType,
  sendPropsGiveUser,
} from '#/api/legacy/props';
import { getUserBaseInfoBySysOriginAccount } from '#/api/legacy/user';
import { getAllowedSysOrigins } from '#/views/system/shared';

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

defineOptions({ name: 'PropsSendTool' });

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

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

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

type RecipientProfile = {
  account: string;
  avatar: string;
  id: string;
  name: string;
  status: 'found' | 'missing';
};

const BADGE_TYPE_VALUE = '__BADGE__';
const GIFT_TYPE_VALUE = '__GIFT__';
const MAX_BATCH_ACCOUNTS = 15;
const RESOURCE_PAGE_SIZE = 72;
const QUICK_DAYS = [1, 7, 15, 30, -1, -7];
const QUICK_GIFT_QUANTITIES = [1, 5, 10, 50, 100];
const USER_AVATAR_FALLBACK =
  'https://dummyimage.com/40x40/e2e8f0/64748b&text=U';

const accessStore = useAccessStore();

const accessCodes = computed(() => accessStore.accessCodes || []);
const sysOriginOptions = computed(() => {
  const options = getAllowedSysOrigins(accessCodes.value);
  return options.length > 0 ? options : getAllowedSysOrigins([]);
});

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

const propsFormLoading = ref(false);
const sourceLoading = ref(false);
const sourceOptions = ref<DisplayResource[]>([]);
const selectedResources = ref<DisplayResource[]>([]);
const resourceKeyword = ref('');
const resourcePage = ref(1);
const recipientLoading = ref(false);
const recipientProfiles = ref<Record<string, RecipientProfile>>({});
let recipientSearchSeq = 0;
let recipientSearchTimer: number | undefined;

const form = reactive({
  exchangeDays: '',
  giftQuantity: 1,
  receiverAccounts: '',
  secondaryType: '',
  sysOrigin: sysOriginOptions.value[0]?.value ?? '',
});

function hasPermission(code: string) {
  const codes = accessCodes.value;
  return codes.length === 0 || codes.includes(code);
}

const canSendProps = computed(() => hasPermission('send:props'));
const canSendBadge = computed(
  () => canSendProps.value || hasPermission('send:props:badge'),
);
const canSendGift = computed(
  () => canSendProps.value || hasPermission('send:props:GIFT'),
);
const canUsePage = computed(
  () => canSendProps.value || canSendBadge.value || canSendGift.value,
);

const typeOptions = computed<TypeOption[]>(() => {
  const options: TypeOption[] = [];
  if (canSendProps.value) {
    options.push(
      ...propsTypeOptions.map((item) => ({
        icon: 'lucide:package',
        kind: 'props' as ResourceKind,
        label: item.name,
        value: String(item.value),
      })),
    );
  }
  if (canSendBadge.value) {
    options.push({
      icon: 'lucide:award',
      kind: 'badge',
      label: '徽章',
      value: BADGE_TYPE_VALUE,
    });
  }
  if (canSendGift.value) {
    options.push({
      icon: 'lucide:gift',
      kind: 'gift',
      label: '礼物',
      value: GIFT_TYPE_VALUE,
    });
  }
  return options;
});

const currentTypeOption = computed(
  () => typeOptions.value.find((item) => item.value === form.secondaryType) || null,
);
const currentTypeLabel = computed(() => currentTypeOption.value?.label || '请选择类型');
const currentAccounts = computed(() => normalizeAccounts(form.receiverAccounts));
const displayedRecipients = computed(() =>
  currentAccounts.value.slice(0, MAX_BATCH_ACCOUNTS).map((account) => {
    return (
      recipientProfiles.value[account] || {
        account,
        avatar: '',
        id: '',
        name: account,
        status: 'missing' as const,
      }
    );
  }),
);
const selectedCount = computed(() => selectedResources.value.length);
const selectedHasGift = computed(() =>
  selectedResources.value.some((item) => item.kind === 'gift'),
);
const selectedHasNonGift = computed(() =>
  selectedResources.value.some((item) => item.kind !== 'gift'),
);
const currentTypeIsGift = computed(() => currentTypeOption.value?.kind === 'gift');
const showGiftQuantity = computed(() => selectedHasGift.value || currentTypeIsGift.value);
const showExchangeDays = computed(
  () => selectedHasNonGift.value || (!selectedHasGift.value && !currentTypeIsGift.value),
);
const sendActionText = computed(() => {
  if (selectedHasGift.value && selectedHasNonGift.value) {
    return Number(form.exchangeDays) < 0 ? '礼物赠送 / 道具回收' : '赠送';
  }
  if (selectedHasGift.value) {
    return '赠送';
  }
  return Number(form.exchangeDays) < 0 ? '回收' : '赠送';
});
const selectedTypeSummary = computed(() => {
  const labels = [
    ...new Set(selectedResources.value.map((item) => item.typeLabel).filter(Boolean)),
  ];
  return labels.length > 0 ? labels.join('、') : '-';
});

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 = (resourcePage.value - 1) * RESOURCE_PAGE_SIZE;
  return filteredResources.value.slice(start, start + RESOURCE_PAGE_SIZE);
});

const selectedResourceKeys = computed(
  () => new Set(selectedResources.value.map((item) => item.key)),
);

watch(
  sysOriginOptions,
  (options) => {
    if (!form.sysOrigin && options[0]?.value) {
      form.sysOrigin = String(options[0].value);
    }
  },
  { immediate: true },
);

watch(
  [currentAccounts, () => form.sysOrigin],
  ([accounts]) => {
    scheduleRecipientLookup(accounts);
  },
  { immediate: true },
);

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

watch(filteredResources, () => {
  const pageCount = Math.max(
    1,
    Math.ceil(filteredResources.value.length / RESOURCE_PAGE_SIZE),
  );
  if (resourcePage.value > pageCount) {
    resourcePage.value = pageCount;
  }
});

function normalizeAccounts(value: string) {
  return value
    .split(/[,，;\s]+/)
    .map((item) => item.trim())
    .filter(Boolean);
}

onBeforeUnmount(() => {
  if (recipientSearchTimer) {
    window.clearTimeout(recipientSearchTimer);
  }
});

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 normalizeRecipientProfile(
  account: string,
  profile?: null | Record<string, any>,
): RecipientProfile {
  const id = firstPresent(profile || {}, ['id', 'userId']);
  const name = firstPresent(profile || {}, ['userNickname', 'nickname', 'name']);
  const profileAccount = firstPresent(profile || {}, [
    'actualAccount',
    'account',
    'shortAccount',
  ]);
  const avatar = firstPresent(profile || {}, ['userAvatar', 'avatar']);

  return {
    account: String(profileAccount || account),
    avatar: String(avatar || ''),
    id: String(id || ''),
    name: String(name || account),
    status: id || profileAccount || name ? 'found' : 'missing',
  };
}

function scheduleRecipientLookup(accounts: string[]) {
  if (recipientSearchTimer) {
    window.clearTimeout(recipientSearchTimer);
  }

  const seq = ++recipientSearchSeq;
  const visibleAccounts = [...new Set(accounts)].slice(0, MAX_BATCH_ACCOUNTS);
  const nextProfiles: Record<string, RecipientProfile> = {};
  visibleAccounts.forEach((account) => {
    const existing = recipientProfiles.value[account];
    if (existing) {
      nextProfiles[account] = existing;
    }
  });
  recipientProfiles.value = nextProfiles;

  if (visibleAccounts.length === 0 || !form.sysOrigin) {
    recipientLoading.value = false;
    return;
  }

  recipientSearchTimer = window.setTimeout(() => {
    void lookupRecipientProfiles(visibleAccounts, seq);
  }, 350);
}

async function lookupRecipientProfiles(accounts: string[], seq: number) {
  recipientLoading.value = true;
  const results = await Promise.allSettled(
    accounts.map(async (account) => {
      const profile = await getUserBaseInfoBySysOriginAccount(form.sysOrigin, account);
      return [account, normalizeRecipientProfile(account, profile)] as const;
    }),
  );

  if (seq !== recipientSearchSeq) {
    return;
  }

  const nextProfiles: Record<string, RecipientProfile> = {};
  results.forEach((result, index) => {
    const account = accounts[index] || '';
    if (!account) {
      return;
    }
    if (result.status === 'fulfilled') {
      nextProfiles[result.value[0]] = result.value[1];
      return;
    }
    nextProfiles[account] = normalizeRecipientProfile(account, null);
  });
  recipientProfiles.value = nextProfiles;
  recipientLoading.value = false;
}

function normalizeDisplayResource(
  item: Record<string, any>,
  kind: ResourceKind,
  secondaryType: 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']),
    badgeTypeLabel: kind === 'badge' ? typeLabel : '',
    cover: String(cover || ''),
    id: id as number | string,
    key: `${kind}-${secondaryType}-${id}`,
    kind,
    name: String(name || (id ? `资源 ${id}` : '-')),
    raw: item,
    secondaryType,
    type: secondaryType,
    typeLabel,
  };
}

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 formatCurrentAccounts() {
  form.receiverAccounts = currentAccounts.value.join(', ');
}

function formatResourceAmount(value: number | string | undefined) {
  if (value === undefined || value === null || String(value).trim() === '') {
    return '-';
  }
  return String(value);
}

function setQuickDays(value: number) {
  form.exchangeDays = String(value);
}

function setQuickGiftQuantity(value: number) {
  form.giftQuantity = value;
}

function selectType(option: TypeOption) {
  if (form.secondaryType === option.value) {
    return;
  }
  form.secondaryType = option.value;
  resourceKeyword.value = '';
  resourcePage.value = 1;
  sourceOptions.value = [];
  void loadSources();
}

async function loadSources() {
  const type = currentTypeOption.value;
  if (!type || !form.sysOrigin) {
    sourceOptions.value = [];
    return;
  }

  sourceLoading.value = true;
  try {
    if (type.kind === 'badge') {
      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,
            ),
          );
        }),
      );
      sourceOptions.value = uniqueResources(results.flat());
      return;
    }

    if (type.kind === 'gift') {
      const rows = await listGiftBySysOrigin(form.sysOrigin);
      sourceOptions.value = (rows || []).map((item) =>
        normalizeDisplayResource(item, 'gift', 'GIFT', '礼物'),
      );
      return;
    }

    const rows = await listNotFamilyBySysOriginType(form.sysOrigin, type.value);
    sourceOptions.value = (rows || []).map((item) =>
      normalizeDisplayResource(item, 'props', type.value, type.label),
    );
  } finally {
    sourceLoading.value = false;
  }
}

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

function removeSelectedResource(resource: DisplayResource) {
  selectedResources.value = selectedResources.value.filter(
    (item) => item.key !== resource.key,
  );
}

function clearSelectedResources() {
  selectedResources.value = [];
}

function validateAccounts(value: string) {
  const accounts = normalizeAccounts(value);
  if (accounts.length === 0) {
    message.warning('请输入接收人短账号');
    return null;
  }
  if (accounts.length > MAX_BATCH_ACCOUNTS) {
    message.warning(`一批最多 ${MAX_BATCH_ACCOUNTS} 个接收人`);
    return null;
  }
  return accounts;
}

function validateBeforeSend() {
  const accounts = validateAccounts(form.receiverAccounts);
  if (!accounts) {
    return null;
  }
  if (!form.sysOrigin) {
    message.warning('系统参数为空，请刷新页面后重试');
    return null;
  }
  if (selectedResources.value.length === 0) {
    message.warning('请选择资源');
    return null;
  }
  if (
    selectedHasNonGift.value &&
    (form.exchangeDays === '' || Number.isNaN(Number(form.exchangeDays)))
  ) {
    message.warning('请输入有效天数');
    return null;
  }
  if (
    selectedHasGift.value &&
    (!Number.isFinite(Number(form.giftQuantity)) || Number(form.giftQuantity) <= 0)
  ) {
    message.warning('请输入礼物数量');
    return null;
  }
  return accounts;
}

function buildSendPayload(resource: DisplayResource, accounts: string[]) {
  if (resource.kind === 'gift') {
    const quantity = Number(form.giftQuantity);
    return {
      content: resource.id,
      exchangeDays: quantity,
      quantity,
      receiverAccounts: accounts.join(','),
      secondaryType: 'GIFT',
      sysOrigin: form.sysOrigin,
      type: 'GIFT',
    };
  }

  const payload: Record<string, any> = {
    content: resource.id,
    exchangeDays: Number(form.exchangeDays),
    receiverAccounts: accounts.join(','),
    secondaryType: resource.secondaryType,
    sysOrigin: form.sysOrigin,
    type: resource.kind === 'badge' ? 'BADGE' : 'PROPS',
  };

  return payload;
}

async function handleSendProps() {
  const accounts = validateBeforeSend();
  if (!accounts) {
    return;
  }

  propsFormLoading.value = true;
  try {
    for (const resource of selectedResources.value) {
      const invalidAccounts = await sendPropsGiveUser(
        buildSendPayload(resource, accounts),
      );
      if (invalidAccounts) {
        message.error(
          `资源「${resource.name}」无效短账号: ${invalidAccounts}，请处理后再将当前批次所有短账号重新发送。`,
        );
        return;
      }
    }
    message.success(`发送成功，共发送 ${selectedResources.value.length} 个资源`);
    form.receiverAccounts = '';
  } finally {
    propsFormLoading.value = false;
  }
}

function resetCurrentForm() {
  form.receiverAccounts = '';
  form.secondaryType = '';
  form.exchangeDays = '';
  form.giftQuantity = 1;
  resourceKeyword.value = '';
  resourcePage.value = 1;
  sourceOptions.value = [];
  selectedResources.value = [];
}
</script>

<template>
  <Page title="资源赠送">
    <div v-if="canUsePage" class="send-tool">
      <div class="send-layout">
        <section class="send-main">
          <Form class="send-form" layout="vertical">
            <div class="control-panel">
              <div class="receiver-line">
                <span class="control-label">接收人</span>
                <Input
                  v-model:value="form.receiverAccounts"
                  allow-clear
                  class="receiver-input"
                  placeholder="输入短账号，逗号/空格分隔"
                  @blur="formatCurrentAccounts"
                  @press-enter="formatCurrentAccounts"
                />
                <Tag
                  :color="
                    currentAccounts.length > MAX_BATCH_ACCOUNTS ? 'error' : 'blue'
                  "
                  class="receiver-count"
                >
                  {{ currentAccounts.length }}/{{ MAX_BATCH_ACCOUNTS }}
                </Tag>
                <div v-if="currentAccounts.length > 0" class="recipient-strip">
                  <span v-if="recipientLoading" class="recipient-state">
                    检索中
                  </span>
                  <span
                    v-for="(recipient, index) in displayedRecipients"
                    :key="`${recipient.account}-${index}`"
                    :class="{
                      'recipient-chip--missing': recipient.status === 'missing',
                    }"
                    class="recipient-chip"
                  >
                    <img
                      :src="recipient.avatar || USER_AVATAR_FALLBACK"
                      alt=""
                      class="recipient-chip__avatar"
                    />
                    <span class="recipient-chip__name">{{ recipient.name }}</span>
                    <span class="recipient-chip__account">
                      {{ recipient.account }}
                    </span>
                  </span>
                  <Tag
                    v-if="currentAccounts.length > MAX_BATCH_ACCOUNTS"
                    color="error"
                  >
                    超出 {{ currentAccounts.length - MAX_BATCH_ACCOUNTS }} 个
                  </Tag>
                </div>
              </div>

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

            <div class="resource-section">
              <div class="resource-head">
                <div class="field-head">
                  <span>资源列表</span>
                  <small>
                    当前 {{ currentTypeLabel }}，共 {{ filteredResources.length }} 个，已选
                    {{ selectedCount }} 个
                  </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__price">
                      底价 {{ formatResourceAmount(resource.amount) }}
                    </span>
                  </button>
                </div>
                <Empty
                  v-else
                  :description="form.secondaryType ? '暂无可选资源' : '请选择类型'"
                  class="resource-empty"
                />
              </Spin>

              <div v-if="filteredResources.length > RESOURCE_PAGE_SIZE" class="pager">
                <Pagination
                  :current="resourcePage"
                  :page-size="RESOURCE_PAGE_SIZE"
                  :total="filteredResources.length"
                  size="small"
                  @change="(page: number) => (resourcePage = page)"
                />
              </div>
            </div>
          </Form>
        </section>

        <aside class="send-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">{{ selectedCount }}</Tag>
                <button
                  v-if="selectedResources.length > 0"
                  class="selected-clear"
                  type="button"
                  @click="clearSelectedResources"
                >
                  清空
                </button>
              </div>
            </div>
            <div v-if="selectedResources.length > 0" class="selected-list">
              <div
                v-for="resource in selectedResources"
                :key="resource.key"
                class="selected-item"
              >
                <RewardIcon :item="resource" :size="36" />
                <div class="selected-item__body">
                  <strong>{{ resource.name }}</strong>
                  <span>
                    {{ resource.typeLabel }} · 底价
                    {{ formatResourceAmount(resource.amount) }}
                  </span>
                </div>
                <button
                  aria-label="移除资源"
                  class="selected-item__remove"
                  type="button"
                  @click="removeSelectedResource(resource)"
                >
                  <IconifyIcon icon="lucide:x" />
                </button>
              </div>
            </div>
            <div v-else class="summary-empty">未选择资源</div>
          </div>

          <div v-if="showExchangeDays" class="summary-control summary-control--days">
            <div class="summary-control__row">
              <label class="summary-control__label" for="props-send-days">
                有效天数
              </label>
              <InputNumber
                id="props-send-days"
                v-model:value="form.exchangeDays"
                :controls="false"
                :precision="0"
                class="summary-days-input"
                placeholder="正数赠送，负数回收"
              />
            </div>
            <div class="quick-days summary-quick-days">
              <button
                v-for="day in QUICK_DAYS"
                :key="day"
                :class="{ 'quick-day--active': Number(form.exchangeDays) === day }"
                class="quick-day"
                type="button"
                @click="setQuickDays(day)"
              >
                {{ day > 0 ? `${day}天` : `${day}天` }}
              </button>
            </div>
          </div>

          <div v-if="showGiftQuantity" class="summary-control summary-control--days">
            <div class="summary-control__row">
              <label class="summary-control__label" for="gift-send-quantity">
                礼物数量
              </label>
              <InputNumber
                id="gift-send-quantity"
                v-model:value="form.giftQuantity"
                :controls="false"
                :min="1"
                :precision="0"
                class="summary-days-input"
                placeholder="请输入数量"
              />
            </div>
            <div class="quick-days summary-quick-days">
              <button
                v-for="quantity in QUICK_GIFT_QUANTITIES"
                :key="quantity"
                :class="{ 'quick-day--active': Number(form.giftQuantity) === quantity }"
                class="quick-day"
                type="button"
                @click="setQuickGiftQuantity(quantity)"
              >
                {{ quantity }}
              </button>
            </div>
          </div>

          <dl class="summary-list">
            <div>
              <dt>接收人数</dt>
              <dd>{{ currentAccounts.length }}</dd>
            </div>
            <div>
              <dt>资源类型</dt>
              <dd>{{ selectedTypeSummary }}</dd>
            </div>
            <div>
              <dt>动作</dt>
              <dd>{{ sendActionText }}</dd>
            </div>
          </dl>

          <Button
            :loading="propsFormLoading"
            block
            class="summary-send"
            size="large"
            type="primary"
            @click="handleSendProps"
          >
            <template #icon>
              <IconifyIcon icon="lucide:send" />
            </template>
            发送
          </Button>
          <Button block @click="resetCurrentForm">
            <template #icon>
              <IconifyIcon icon="lucide:rotate-ccw" />
            </template>
            重置当前
          </Button>
        </aside>
      </div>
    </div>
    <Empty v-else description="暂无赠送权限" />
  </Page>
</template>

<style scoped>
.send-tool {
  display: grid;
}

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

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

.send-main {
  padding: 12px 14px;
}

.send-form {
  display: grid;
  gap: 10px;
}

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

.control-panel {
  background: #fbfcfe;
  border: 1px solid #edf0f3;
  border-radius: 8px;
  padding: 10px;
}

.receiver-line {
  align-items: center;
  display: flex;
  gap: 8px;
  min-width: 0;
}

.control-label {
  color: #111827;
  font-weight: 600;
  flex: 0 0 64px;
}

.receiver-input {
  flex: 0 1 320px;
  min-width: 220px;
}

.receiver-count {
  flex: 0 0 auto;
  margin-inline-end: 0;
}

.recipient-strip {
  align-items: center;
  display: flex;
  flex: 1 1 auto;
  gap: 6px;
  min-width: 0;
  overflow-x: auto;
  padding: 1px 0;
  white-space: nowrap;
}

.recipient-state {
  color: #6b7280;
  font-size: 12px;
}

.recipient-chip {
  align-items: center;
  background: #fff;
  border: 1px solid #d9e2ef;
  border-radius: 999px;
  display: inline-flex;
  flex: 0 0 auto;
  gap: 6px;
  height: 30px;
  max-width: 220px;
  padding: 3px 8px 3px 3px;
}

.recipient-chip--missing {
  border-color: #ffd8bf;
  color: #ad4e00;
}

.recipient-chip__avatar {
  border-radius: 50%;
  height: 24px;
  object-fit: cover;
  width: 24px;
}

.recipient-chip__name,
.recipient-chip__account {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.recipient-chip__name {
  color: #111827;
  font-size: 12px;
  font-weight: 600;
  max-width: 88px;
}

.recipient-chip__account {
  color: #6b7280;
  font-size: 11px;
  max-width: 72px;
}

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

.quick-day {
  background: #fff;
  border: 1px solid #d9dfe8;
  border-radius: 6px;
  color: #374151;
  cursor: pointer;
  font-size: 12px;
  height: 30px;
  line-height: 1;
  padding: 0 10px;
}

.quick-day--active {
  background: #e8f2ff;
  border-color: #1677ff;
  color: #0958d9;
}

.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;
}

.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-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: 96px;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  max-height: calc(100vh - 286px);
  min-height: 390px;
  overflow: auto;
  padding: 8px;
}

.resource-icon-card {
  align-items: center;
  background: #fff;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  cursor: pointer;
  display: grid;
  gap: 5px;
  height: 96px;
  justify-items: center;
  min-height: 96px;
  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,
    transform 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 {
  color: #111827;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.3;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.resource-icon-card__price {
  background: #fff7e6;
  border-radius: 999px;
  color: #8c5a00;
  font-size: 11px;
  line-height: 1.25;
  max-width: 100%;
  overflow: hidden;
  padding: 2px 7px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

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

.pager {
  display: flex;
  justify-content: flex-end;
  margin-top: 8px;
}

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

.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(28vh, 220px);
  overflow: auto;
}

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

.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;
}

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

.selected-item__remove:hover {
  color: #d4380d;
}

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

.summary-control {
  background: #fbfcfe;
  border: 1px solid #edf0f3;
  border-radius: 8px;
  display: grid;
  gap: 6px;
  padding: 8px;
}

.summary-control--days {
  gap: 6px;
}

.summary-control__row {
  align-items: center;
  display: grid;
  gap: 8px;
  grid-template-columns: 64px minmax(0, 1fr);
}

.summary-control__label {
  color: #111827;
  font-weight: 600;
}

.summary-days-input {
  width: 100%;
}

.summary-quick-days {
  display: grid;
  gap: 4px;
  grid-template-columns: repeat(6, minmax(0, 1fr));
}

.summary-quick-days .quick-day {
  height: 28px;
  padding: 0 4px;
}

.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: 30px;
}

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

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

.summary-send {
  margin-top: 4px;
}

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

  .send-summary {
    position: static;
  }
}

@media (max-width: 720px) {
  .send-main {
    padding: 14px;
  }

  .receiver-line {
    align-items: stretch;
    display: grid;
    grid-template-columns: 1fr;
  }

  .control-label,
  .receiver-input {
    flex: none;
    width: 100%;
  }

  .resource-head {
    align-items: stretch;
    display: grid;
  }

  .resource-search {
    max-width: none;
  }

  .resource-grid {
    grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
    max-height: none;
  }
}
</style>
