<script lang="ts" setup>
import {
  deleteLink,
  getLinkReferences,
  listLinks,
  refreshLinkReferences,
  updateLink,
} from '@/api';
import LinkFormModal from '@/components/LinkFormModal.vue';
import RecordsDrawer from '@/components/RecordsDrawer.vue';
import type { ProtectedLink, 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 links = ref<ProtectedLink[]>([]);
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 editingLink = ref<ProtectedLink | null>(null);

const recordsVisible = ref(false);
const recordsLink = ref<ProtectedLink | 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 visitUrl(slug: string): string {
  return `${window.location.origin}/link/${slug}`;
}

async function copyVisitUrl(slug: string) {
  const url = visitUrl(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 fetchLinks() {
  loading.value = true;
  try {
    const data = await listLinks();
    links.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 getLinkReferences()) ?? {};
  } catch (e) {
    Toast.error(errorMessage(e));
  } finally {
    referencesLoading.value = false;
  }
}

async function handleRefreshScan() {
  refreshingScan.value = true;
  try {
    references.value = (await refreshLinkReferences()) ?? {};
    Toast.success('引用扫描已刷新');
    fetchLinks();
  } 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() {
  editingLink.value = null;
  formModalVisible.value = true;
}

function handleEdit(link: ProtectedLink) {
  editingLink.value = link;
  formModalVisible.value = true;
}

function handleOpenRecords(link: ProtectedLink) {
  recordsLink.value = link;
  recordsVisible.value = true;
}

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

function handleDelete(link: ProtectedLink) {
  Dialog.warning({
    title: '删除受保护链接',
    description: `确定要删除链接「${link.spec.displayName}」吗？删除后访问链接 /link/${link.spec.slug} 将立即失效。`,
    confirmType: 'danger',
    confirmText: '删除',
    cancelText: '取消',
    onConfirm: async () => {
      try {
        await deleteLink(link.metadata.name);
        pendingDeletes.add(link.metadata.name);
        setTimeout(
          () => pendingDeletes.delete(link.metadata.name),
          3000
        );
        links.value = links.value.filter(
          (r) => r.metadata.name !== link.metadata.name
        );
        Toast.success(`已删除链接「${link.spec.displayName}」`);
        fetchLinks();
      } catch (e) {
        Toast.error(errorMessage(e));
      }
    },
  });
}

function handleSaved(link: ProtectedLink, created: boolean) {
  fetchLinks();
  if (created && link.spec.enabled) {
    Toast.success(`访问链接：/link/${link.spec.slug}`);
  }
}

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

<template>
  <VPageHeader v-if="!embedded" title="链接访问管理" />

  <div class="link-manager-page m-4">
    <VCard>
      <div class="card-toolbar">
        <div class="text-sm text-gray-500">
          共 {{ links.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="
              fetchLinks();
              fetchReferences();
            "
          >
            刷新
          </VButton>
        </VSpace>
      </div>

      <VLoading v-if="loading" />
      <VEmpty
        v-else-if="links.length === 0"
        title="暂无受保护链接"
        message="点击右上角「新建链接」为任意 http/https 地址创建访问门禁"
      />
      <div v-else class="table-wrapper">
        <table class="link-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 links" :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">/link/{{ item.spec.slug }}</code>
                    <VButton
                      size="sm"
                      type="default"
                      ghost
                      @click="copyVisitUrl(item.spec.slug)"
                    >
                      <template #icon>
                        <IconClipboardLine />
                      </template>
                      复制
                    </VButton>
                  </div>
                </td>
                <td>
                  <a
                    class="target-link"
                    :href="item.spec.targetUrl"
                    target="_blank"
                    rel="noopener noreferrer"
                    :title="item.spec.targetUrl"
                  >
                    {{ item.spec.targetUrl }}
                    <IconExternalLinkLine />
                  </a>
                </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?.visitCount ?? 0 }}</td>
                <td>{{ item.stats?.visitorCount ?? 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"
                  >
                    暂无文章引用该链接（可在编辑器中插入 /link/{{
                      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>

    <LinkFormModal
      v-model:visible="formModalVisible"
      :link="editingLink"
      @saved="handleSaved"
    />

    <RecordsDrawer
      v-model:visible="recordsVisible"
      kind="link"
      :resource="recordsLink"
    />
  </div>
</template>

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

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

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

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

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

.target-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #2563eb;
  text-decoration: none;
}

.target-link:hover {
  text-decoration: underline;
}

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