<script lang="ts" setup>
import {
  createResource,
  deleteResource,
  getReferences,
  listResources,
  refreshReferences,
  updateResource,
} from '@/api';
import ResourceFormModal from '@/components/ResourceFormModal.vue';
import RecordsDrawer from '@/components/RecordsDrawer.vue';
import type { DownloadResource, ReferencesMap } from '@/types';
import {
  Dialog,
  IconAddCircle,
  IconClipboardLine,
  IconDeleteBin,
  IconExternalLinkLine,
  IconRefreshLine,
  IconRiPencilFill,
  Toast,
  VButton,
  VCard,
  VEmpty,
  VLoading,
  VPageHeader,
  VSpace,
  VSwitch,
  VTag,
} from '@halo-dev/components';
import { onMounted, ref } from 'vue';

const props = defineProps<{
  embedded?: boolean;
}>();

const resources = ref<DownloadResource[]>([]);
const loading = ref(false);
const references = ref<ReferencesMap>({});
const referencesLoading = ref(false);
const refreshingScan = ref(false);

// 后端删除为异步落库，短时间内列表仍可能返回已删项，在此窗口内过滤掉
const pendingDeletes = new Set<string>();

// 展开引用文章列表的 slug 集合
const expandedSlugs = ref<Set<string>>(new Set());

const formModalVisible = ref(false);
const editingResource = ref<DownloadResource | null>(null);

const recordsVisible = ref(false);
const recordsResource = ref<DownloadResource | null>(null);

function errorMessage(e: unknown): string {
  const err = e as {
    response?: { data?: { detail?: string; title?: string } };
    message?: string;
  };
  return (
    err?.response?.data?.detail ||
    err?.response?.data?.title ||
    err?.message ||
    '请求失败，请稍后重试'
  );
}

function downloadUrl(slug: string): string {
  return `${window.location.origin}/download/${slug}`;
}

async function copyDownloadUrl(slug: string) {
  const url = downloadUrl(slug);
  try {
    await navigator.clipboard.writeText(url);
    Toast.success('下载链接已复制');
  } catch {
    // 剪贴板 API 不可用时的降级方案
    const textarea = document.createElement('textarea');
    textarea.value = url;
    document.body.appendChild(textarea);
    textarea.select();
    try {
      document.execCommand('copy');
      Toast.success('下载链接已复制');
    } catch {
      Toast.error('复制失败，请手动复制');
    }
    document.body.removeChild(textarea);
  }
}

async function fetchResources() {
  loading.value = true;
  try {
    const data = await listResources();
    resources.value = (data.items ?? []).filter(
      (r) => !pendingDeletes.has(r.metadata.name)
    );
  } catch (e) {
    Toast.error(errorMessage(e));
  } finally {
    loading.value = false;
  }
}

async function fetchReferences() {
  referencesLoading.value = true;
  try {
    references.value = (await getReferences()) ?? {};
  } catch (e) {
    Toast.error(errorMessage(e));
  } finally {
    referencesLoading.value = false;
  }
}

async function handleRefreshScan() {
  refreshingScan.value = true;
  try {
    references.value = (await refreshReferences()) ?? {};
    Toast.success('引用扫描已刷新');
    fetchResources();
  } catch (e) {
    Toast.error(errorMessage(e));
  } finally {
    refreshingScan.value = false;
  }
}

function toggleExpand(slug: string) {
  const next = new Set(expandedSlugs.value);
  if (next.has(slug)) {
    next.delete(slug);
  } else {
    next.add(slug);
  }
  expandedSlugs.value = next;
}

function handleCreate() {
  editingResource.value = null;
  formModalVisible.value = true;
}

function handleEdit(resource: DownloadResource) {
  editingResource.value = resource;
  formModalVisible.value = true;
}

function handleOpenRecords(resource: DownloadResource) {
  recordsResource.value = resource;
  recordsVisible.value = true;
}

async function handleToggleEnabled(resource: DownloadResource, value: boolean) {
  const previous = resource.spec.enabled;
  resource.spec.enabled = value;
  try {
    await updateResource(resource.metadata.name, {
      ...resource.spec,
      enabled: value,
    });
    Toast.success(value ? '已启用' : '已停用');
  } catch (e) {
    resource.spec.enabled = previous;
    Toast.error(errorMessage(e));
    fetchResources();
  }
}

function handleDelete(resource: DownloadResource) {
  Dialog.warning({
    title: '删除下载资源',
    description: `确定要删除资源「${resource.spec.displayName}」吗？删除后下载链接 /download/${resource.spec.slug} 将立即失效。`,
    confirmType: 'danger',
    confirmText: '删除',
    cancelText: '取消',
    onConfirm: async () => {
      try {
        await deleteResource(resource.metadata.name);
        pendingDeletes.add(resource.metadata.name);
        setTimeout(
          () => pendingDeletes.delete(resource.metadata.name),
          3000
        );
        resources.value = resources.value.filter(
          (r) => r.metadata.name !== resource.metadata.name
        );
        Toast.success(`已删除资源「${resource.spec.displayName}」`);
        fetchResources();
      } catch (e) {
        Toast.error(errorMessage(e));
      }
    },
  });
}

function handleSaved(resource: DownloadResource, created: boolean) {
  fetchResources();
  if (created && resource.spec.enabled) {
    Toast.success(`下载链接：/download/${resource.spec.slug}`);
  }
}

onMounted(() => {
  fetchResources();
  fetchReferences();
});
</script>

<template>
  <VPageHeader v-if="!embedded" title="下载管理" />

  <div class="download-manager-page m-4">
    <VCard>
      <div class="card-toolbar">
        <div class="text-sm text-gray-500">
          共 {{ resources.length }} 个下载资源
        </div>
        <VSpace>
          <VButton size="sm" type="primary" @click="handleCreate">
            <template #icon>
              <IconAddCircle />
            </template>
            新建资源
          </VButton>
          <VButton
            size="sm"
            type="secondary"
            :loading="refreshingScan"
            @click="handleRefreshScan"
          >
            <template #icon>
              <IconRefreshLine />
            </template>
            刷新引用扫描
          </VButton>
          <VButton
            size="sm"
            type="default"
            :loading="loading || referencesLoading"
            @click="
              fetchResources();
              fetchReferences();
            "
          >
            刷新
          </VButton>
        </VSpace>
      </div>

      <VLoading v-if="loading" />
      <VEmpty
        v-else-if="resources.length === 0"
        title="暂无下载资源"
        message="点击右上角「新建资源」创建第一个资源下载链接"
      />
      <div v-else class="table-wrapper">
        <table class="resource-table">
          <thead>
            <tr>
              <th>名称</th>
              <th>下载链接</th>
              <th>附件</th>
              <th>邮箱验证</th>
              <th>启用</th>
              <th>引用文章</th>
              <th>下载数</th>
              <th>下载人数</th>
              <th class="w-56">操作</th>
            </tr>
          </thead>
          <tbody>
            <template v-for="item in resources" :key="item.metadata.name">
              <tr>
                <td class="font-medium">
                  <div>{{ item.spec.displayName }}</div>
                  <div
                    v-if="item.spec.description"
                    class="text-xs text-gray-400 desc-line"
                    :title="item.spec.description"
                  >
                    {{ item.spec.description }}
                  </div>
                </td>
                <td>
                  <div class="link-cell">
                    <code class="link-code">/download/{{ item.spec.slug }}</code>
                    <VButton
                      size="sm"
                      type="default"
                      ghost
                      @click="copyDownloadUrl(item.spec.slug)"
                    >
                      <template #icon>
                        <IconClipboardLine />
                      </template>
                      复制
                    </VButton>
                  </div>
                </td>
                <td class="cell-ellipsis" :title="item.spec.attachmentName">
                  {{ item.spec.attachmentName || '-' }}
                </td>
                <td>
                  <VTag :theme="item.spec.requireEmailVerify ? 'primary' : 'default'">
                    {{ item.spec.requireEmailVerify ? '需要' : '不需要' }}
                  </VTag>
                </td>
                <td>
                  <VSwitch
                    :model-value="item.spec.enabled ?? false"
                    @change="(value: boolean) => handleToggleEnabled(item, value)"
                  />
                </td>
                <td>
                  <VButton
                    size="sm"
                    type="default"
                    ghost
                    @click="toggleExpand(item.spec.slug)"
                  >
                    {{ item.stats?.referenceCount ?? 0 }} 篇
                    {{ expandedSlugs.has(item.spec.slug) ? '▲' : '▼' }}
                  </VButton>
                </td>
                <td>{{ item.status?.downloadCount ?? 0 }}</td>
                <td>{{ item.stats?.downloaderCount ?? 0 }}</td>
                <td>
                  <VSpace>
                    <VButton
                      size="sm"
                      type="default"
                      @click="handleOpenRecords(item)"
                    >
                      记录
                    </VButton>
                    <VButton
                      size="sm"
                      type="secondary"
                      @click="handleEdit(item)"
                    >
                      <template #icon>
                        <IconRiPencilFill />
                      </template>
                      编辑
                    </VButton>
                    <VButton
                      size="sm"
                      type="danger"
                      ghost
                      @click="handleDelete(item)"
                    >
                      <template #icon>
                        <IconDeleteBin />
                      </template>
                      删除
                    </VButton>
                  </VSpace>
                </td>
              </tr>
              <tr v-if="expandedSlugs.has(item.spec.slug)" class="refs-row">
                <td colspan="9">
                  <div
                    v-if="(references[item.spec.slug] ?? []).length === 0"
                    class="text-sm text-gray-400 refs-empty"
                  >
                    暂无文章引用该资源（可在编辑器中插入 /download/{{
                      item.spec.slug
                    }}
                    链接后点击「刷新引用扫描」）
                  </div>
                  <ul v-else class="refs-list">
                    <li
                      v-for="refItem in references[item.spec.slug]"
                      :key="refItem.postName"
                    >
                      <span class="refs-title">{{ refItem.title }}</span>
                      <a
                        class="refs-link"
                        :href="refItem.editorUrl"
                        target="_blank"
                        rel="noopener noreferrer"
                      >
                        <IconExternalLinkLine /> 编辑器
                      </a>
                      <a
                        class="refs-link"
                        :href="refItem.permalink"
                        target="_blank"
                        rel="noopener noreferrer"
                      >
                        <IconExternalLinkLine /> 访问
                      </a>
                    </li>
                  </ul>
                </td>
              </tr>
            </template>
          </tbody>
        </table>
      </div>
    </VCard>

    <ResourceFormModal
      v-model:visible="formModalVisible"
      :resource="editingResource"
      @saved="handleSaved"
    />

    <RecordsDrawer
      v-model:visible="recordsVisible"
      :resource="recordsResource"
    />
  </div>
</template>

<style scoped>
.card-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}

.table-wrapper {
  overflow-x: auto;
}

.resource-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}

.resource-table th,
.resource-table td {
  padding: 10px 12px;
  text-align: left;
  border-bottom: 1px solid #f0f0f0;
  vertical-align: middle;
  white-space: nowrap;
}

.resource-table th {
  color: #6b7280;
  font-weight: 500;
  background: #fafafa;
}

.link-cell {
  display: flex;
  align-items: center;
  gap: 8px;
}

.link-code {
  background: #f3f4f6;
  border-radius: 4px;
  padding: 2px 6px;
  font-size: 12px;
}

.cell-ellipsis {
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.desc-line {
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.refs-row td {
  background: #fafafa;
  white-space: normal;
}

.refs-empty {
  padding: 4px 0;
}

.refs-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.refs-list li {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 4px 0;
}

.refs-title {
  font-weight: 500;
}

.refs-link {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  color: #2563eb;
  font-size: 13px;
  text-decoration: none;
}

.refs-link:hover {
  text-decoration: underline;
}
</style>
