<script lang="ts" setup>
import {
  deleteLinkRecord,
  deleteRecord,
  linkRecordsExportUrl,
  listLinkRecords,
  listRecords,
  recordsExportUrl,
} from '@/api';
import type { RecordSubject } from '@/types';
import {
  Dialog,
  IconDeleteBin,
  IconRefreshLine,
  IconRiUpload2Fill,
  Toast,
  VButton,
  VEmpty,
  VLoading,
  VModal,
  VPagination,
  VSpace,
} from '@halo-dev/components';
import { computed, ref, watch } from 'vue';

// 下载/链接记录取出的公共字段（时间统一为 time）
interface RecordItem {
  metadata: {
    name: string;
    [key: string]: unknown;
  };
  spec: {
    email?: string;
    ip?: string;
    userAgent?: string;
    time?: string;
  };
}

const props = defineProps<{
  visible: boolean;
  resource: RecordSubject | null;
  kind?: 'download' | 'link';
}>();

const emit = defineEmits<{
  (e: 'update:visible', value: boolean): void;
}>();

const isLink = computed(() => props.kind === 'link');

const records = ref<RecordItem[]>([]);
const loading = ref(false);
const page = ref(1);
const size = ref(20);
const total = ref(0);

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

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 formatTime(iso?: string): string {
  if (!iso) {
    return '-';
  }
  const date = new Date(iso);
  if (Number.isNaN(date.getTime())) {
    return iso;
  }
  return date.toLocaleString('zh-CN', { hour12: false });
}

async function fetchRecords() {
  if (!props.resource) {
    return;
  }
  loading.value = true;
  try {
    const slug = props.resource.spec.slug ?? '';
    const params = {
      page: page.value,
      size: size.value,
    };
    const raw = isLink.value
      ? await listLinkRecords({ ...params, linkSlug: slug })
      : await listRecords({ ...params, resourceSlug: slug });
    records.value = (raw.items ?? [])
      .filter((r) => !pendingDeletes.has(r.metadata.name))
      .map((r) => ({
        metadata: { name: r.metadata.name },
        spec: {
          email: r.spec.email,
          ip: r.spec.ip,
          userAgent: r.spec.userAgent,
          time:
            'visitedAt' in r.spec
              ? (r.spec as { visitedAt?: string }).visitedAt
              : (r.spec as { downloadedAt?: string }).downloadedAt,
        },
      }));
    total.value = raw.total ?? 0;
  } catch (e) {
    Toast.error(errorMessage(e));
  } finally {
    loading.value = false;
  }
}

function handleExport() {
  // 直接导航下载（console 端点接受 session cookie）
  const url = isLink.value
    ? linkRecordsExportUrl(props.resource?.spec.slug)
    : recordsExportUrl(props.resource?.spec.slug);
  window.open(url, '_blank');
}

function handleDelete(record: RecordItem) {
  Dialog.warning({
    title: isLink.value ? '删除访问记录' : '删除下载记录',
    description: '确定要删除这条记录吗？删除后不可恢复。',
    confirmType: 'danger',
    confirmText: '删除',
    cancelText: '取消',
    onConfirm: async () => {
      try {
        if (isLink.value) {
          await deleteLinkRecord(record.metadata.name);
        } else {
          await deleteRecord(record.metadata.name);
        }
        // 删除当前页最后一条时回退一页
        if (records.value.length === 1 && page.value > 1) {
          page.value -= 1;
        }
        pendingDeletes.add(record.metadata.name);
        setTimeout(() => pendingDeletes.delete(record.metadata.name), 3000);
        records.value = records.value.filter(
          (r) => r.metadata.name !== record.metadata.name
        );
        Toast.success('记录已删除');
        fetchRecords();
      } catch (e) {
        Toast.error(errorMessage(e));
      }
    },
  });
}

watch(
  () => [props.visible, props.resource?.metadata.name],
  ([visible]) => {
    if (visible) {
      page.value = 1;
      fetchRecords();
    }
  }
);
</script>

<template>
  <VModal
    :visible="visible"
    :title="`${isLink ? '访问' : '下载'}记录${resource ? ` - ${resource.spec.displayName}` : ''}`"
    :width="960"
    mount-to-body
    @update:visible="emit('update:visible', $event)"
    @close="emit('update:visible', false)"
  >
    <div class="records-toolbar">
      <div class="text-sm text-gray-500">共 {{ total }} 条记录</div>
      <VSpace>
        <VButton size="sm" type="default" @click="handleExport">
          <template #icon>
            <IconRiUpload2Fill />
          </template>
          导出 CSV
        </VButton>
        <VButton
          size="sm"
          type="secondary"
          :loading="loading"
          @click="fetchRecords"
        >
          <template #icon>
            <IconRefreshLine />
          </template>
          刷新
        </VButton>
      </VSpace>
    </div>

    <VLoading v-if="loading" />
    <VEmpty
      v-else-if="records.length === 0"
      :title="isLink ? '暂无访问记录' : '暂无下载记录'"
      :message="isLink ? '该链接还没有产生访问' : '该资源还没有产生下载'"
    />
    <div v-else class="table-wrapper">
      <table class="records-table">
        <thead>
          <tr>
            <th>时间</th>
            <th>邮箱</th>
            <th>IP</th>
            <th>User-Agent</th>
            <th class="w-24">操作</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="record in records" :key="record.metadata.name">
            <td>{{ formatTime(record.spec.time) }}</td>
            <td>{{ record.spec.email || '匿名' }}</td>
            <td>{{ record.spec.ip || '-' }}</td>
            <td class="ua-cell" :title="record.spec.userAgent">
              {{ record.spec.userAgent || '-' }}
            </td>
            <td>
              <VButton
                size="sm"
                type="danger"
                ghost
                @click="handleDelete(record)"
              >
                <template #icon>
                  <IconDeleteBin />
                </template>
                删除
              </VButton>
            </td>
          </tr>
        </tbody>
      </table>
    </div>

    <div v-if="total > 0" class="records-pagination">
      <VPagination
        v-model:page="page"
        v-model:size="size"
        :total="total"
        :size-options="[20, 50, 100]"
        show-total
        @change="fetchRecords"
      />
    </div>
  </VModal>
</template>

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

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

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

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

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

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

.records-pagination {
  display: flex;
  justify-content: flex-end;
  margin-top: 12px;
}
</style>
