<script setup lang="ts">
import { computed, h, onMounted, reactive, ref, watch } from 'vue'
import type { DataTableColumns } from 'naive-ui'
import { ApiCode } from '@/config'
import { exportVaultTransactions, fetchVaultTransactions } from '@/service/vault'
import { useVaultStore } from '@/store/vault'
import type { VaultTransactionItem } from '@/types/vault'

const { t } = useI18n()
const message = useMessage()
const vault = useVaultStore()

const loading = ref(false)
const exporting = ref(false)
const rows = ref<VaultTransactionItem[]>([])

const pagination = reactive({
  page: 1,
  pageSize: 10,
  itemCount: 0,
  showSizePicker: true,
  pageSizes: [10, 20, 50],
  onUpdatePage: (p: number) => {
    pagination.page = p
    void load()
  },
  onUpdatePageSize: (size: number) => {
    pagination.pageSize = size
    pagination.page = 1
    void load()
  },
})
const ETH_TX_BASE_URL = 'https://etherscan.io/tx/'
const TRON_TX_BASE_URL = 'https://tronscan.org/#/transaction/'

const filters = reactive<{
  senderLabel: string | null
  recipientLabel: string | null
  senderAddress: string | null
  recipientAddress: string | null
  timeRange: [number, number] | null
}>({
  senderLabel: null,
  recipientLabel: null,
  senderAddress: null,
  recipientAddress: null,
  timeRange: null,
})

function formatDash(v: unknown): string {
  if (v == null || v === '') return '—'
  return String(v)
}

function formatAmount(v: string | number | undefined): string {
  if (v == null || v === '') return '—'
  return String(v)
}

/** 兼容秒级/毫秒级时间戳与 ISO 字符串 输出yyyy-MM-dd HH:mm:ss 格式 */
function formatTimestamp(v: string | number | undefined): string {
  if (v == null || v === '') return '—'
  const format = (d: Date) => {
    const pad = (n: number) => String(n).padStart(2, '0')
    return (
      `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}` +
      ` ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
    )
  }
  if (typeof v === 'string' && Number.isNaN(Number(v))) {
    const d = new Date(v)
    return Number.isNaN(d.getTime()) ? v : format(d)
  }
  const n = typeof v === 'number' ? v : Number(v)
  if (Number.isNaN(n)) return String(v)
  const ms = n < 1e12 ? n * 1000 : n
  const d = new Date(ms)
  return Number.isNaN(d.getTime()) ? String(v) : format(d)
}

// function boolText(v: boolean | undefined): string {
//   if (v === true) return t('vaultTx.boolYes')
//   if (v === false) return t('vaultTx.boolNo')
//   return '—'
// }

/** 各列 width 之和，供 scroll-x 使用，保证超出视口时可横向滚动看全列 */
const VAULT_TX_COL_WIDTHS = [
  120, 186, 200, 160,/* 120,*/ 96, 140, 200, 160, /*120,*/ 96, 140, 120, 112, 128, 96, 260,
] as const

const tableScrollX = VAULT_TX_COL_WIDTHS.reduce((a, w) => a + w, 0) + 120

/** 表头与单元格均居中（titleAlign / align: center） */
const columns = computed<DataTableColumns<VaultTransactionItem>>(() => [
  {
    title: () => t('vaultTx.colStatus'),
    key: 'status',
    width: 120,
    titleAlign: 'center',
    align: 'center',
    ellipsis: { tooltip: true },
    render: (row) =>
      h('span', { class: 'vault-tx__cell-text vault-tx__cell-status' }, formatDash(row.status)),
  },
  {
    title: () => t('vaultTx.colCreated'),
    key: 'createdTimestamp',
    width: 186,
    titleAlign: 'center',
    align: 'center',
    render: (row) =>
      h('span', { class: 'vault-tx__cell-text vault-tx__cell-mono' }, formatTimestamp(row.createdTimestamp)),
  },
  {
    title: () => t('vaultTx.colSenderAddr'),
    key: 'senderAddress',
    width: 200,
    titleAlign: 'center',
    align: 'center',
    ellipsis: { tooltip: true },
    render: (row) =>
      h('span', { class: 'vault-tx__cell-text vault-tx__cell-mono' }, formatDash(row.senderAddress)),
  },
  {
    title: () => t('vaultTx.colSenderLabel'),
    key: 'senderLabel',
    width: 160,
    titleAlign: 'center',
    align: 'center',
    ellipsis: { tooltip: true },
    render: (row) => h('span', { class: 'vault-tx__cell-text' }, formatDash(row.senderLabel)),
  },
  // {
  //   title: () => t('vaultTx.colSenderInternal'),
  //   key: 'senderIsVaultAddress',
  //   width: 120,
  //   titleAlign: 'center',
  //   align: 'center',
  //   render: (row) =>
  //     h('span', { class: 'vault-tx__cell-text' }, boolText(row.senderIsVaultAddress)),
  // },
  {
    title: () => t('vaultTx.colSenderUnit'),
    key: 'senderAmountUnit',
    width: 96,
    titleAlign: 'center',
    align: 'center',
    ellipsis: { tooltip: true },
    render: (row) =>
      h('span', { class: 'vault-tx__cell-text vault-tx__cell-unit' }, formatDash(row.senderAmountUnit)),
  },
  {
    title: () => t('vaultTx.colSenderAmount'),
    key: 'senderAmount',
    width: 140,
    titleAlign: 'center',
    align: 'center',
    render: (row) =>
      h('span', { class: 'vault-tx__cell-num' }, formatAmount(row.senderAmount)),
  },
  {
    title: () => t('vaultTx.colRecipientAddr'),
    key: 'recipientAddress',
    width: 200,
    titleAlign: 'center',
    align: 'center',
    ellipsis: { tooltip: true },
    render: (row) =>
      h('span', { class: 'vault-tx__cell-text vault-tx__cell-mono' }, formatDash(row.recipientAddress)),
  },
  {
    title: () => t('vaultTx.colRecipientLabel'),
    key: 'recipientLabel',
    width: 160,
    titleAlign: 'center',
    align: 'center',
    ellipsis: { tooltip: true },
    render: (row) => h('span', { class: 'vault-tx__cell-text' }, formatDash(row.recipientLabel)),
  },
  // {
  //   title: () => t('vaultTx.colRecipientInternal'),
  //   key: 'recipientIsVaultAddress',
  //   width: 120,
  //   titleAlign: 'center',
  //   align: 'center',
  //   render: (row) =>
  //     h('span', { class: 'vault-tx__cell-text' }, boolText(row.recipientIsVaultAddress)),
  // },
  {
    title: () => t('vaultTx.colRecipientUnit'),
    key: 'recipientAmountUnit',
    width: 96,
    titleAlign: 'center',
    align: 'center',
    ellipsis: { tooltip: true },
    render: (row) =>
      h('span', { class: 'vault-tx__cell-text vault-tx__cell-unit' }, formatDash(row.recipientAmountUnit)),
  },
  {
    title: () => t('vaultTx.colRecipientAmount'),
    key: 'recipientAmount',
    width: 140,
    titleAlign: 'center',
    align: 'center',
    render: (row) =>
      h('span', { class: 'vault-tx__cell-num' }, formatAmount(row.recipientAmount)),
  },
  {
    title: () => t('vaultTx.colBlockchain'),
    key: 'blockchain',
    width: 120,
    titleAlign: 'center',
    align: 'center',
    ellipsis: { tooltip: true },
    render: (row) =>
      h('span', { class: 'vault-tx__cell-text' }, formatDash(row.blockchain)),
  },
  // {
  //   title: () => t('vaultTx.colBlockHeight'),
  //   key: 'minedInBlockHeight',
  //   width: 112,
  //   titleAlign: 'center',
  //   align: 'center',
  //   render: (row) =>
  //     h('span', { class: 'vault-tx__cell-num' }, formatDash(row.minedInBlockHeight)),
  // },
  {
    title: () => t('vaultTx.colFee'),
    key: 'feeAmount',
    width: 128,
    titleAlign: 'center',
    align: 'center',
    render: (row) =>
      h('span', { class: 'vault-tx__cell-num' }, formatAmount(row.feeAmount)),
  },
  {
    title: () => t('vaultTx.colFeeUnit'),
    key: 'feeAmountUnit',
    width: 96,
    titleAlign: 'center',
    align: 'center',
    ellipsis: { tooltip: true },
    render: (row) =>
      h('span', { class: 'vault-tx__cell-text vault-tx__cell-unit' }, formatDash(row.feeAmountUnit)),
  },
  {
    title: () => t('vaultTx.colTxId'),
    key: 'transactionId',
    width: 260,
    titleAlign: 'center',
    align: 'center',
    ellipsis: { tooltip: true },
    render: (row) => {
      const txid = row.transactionId?.trim()
      if (!txid) return h('span', { class: 'vault-tx__cell-text vault-tx__cell-mono' }, '—')
      const unit = row.blockchain?.trim()
      const baseUrl = unit === 'ethereum' ? ETH_TX_BASE_URL : TRON_TX_BASE_URL
      return h(
        'a',
        {
          class: 'vault-tx__cell-text vault-tx__cell-mono vault-tx__cell-link',
          href: `${baseUrl}${encodeURIComponent(txid)}`,
          target: '_blank',
          rel: 'noopener noreferrer',
        },
        txid
      )
    },
  },
])

async function load(): Promise<void> {
  if (vault.currentVaultId == null) {
    rows.value = []
    pagination.itemCount = 0
    return
  }
  loading.value = true
  try {
    let startTime: string | null = null
    let endTime: string | null = null
    if (filters.timeRange?.[0] != null) {
      const d = new Date(filters.timeRange[0])
      const pad = (n: number) => String(n).padStart(2, '0')
      startTime = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} 00:00:00`
    }
    if (filters.timeRange?.[1] != null) {
      const d = new Date(filters.timeRange[1])
      const pad = (n: number) => String(n).padStart(2, '0')
      endTime = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} 23:59:59`
    }
    const res = await fetchVaultTransactions({
      vaultId: vault.currentVaultId,
      senderLabel: filters.senderLabel,
      recipientLabel: filters.recipientLabel,
      senderAddress: filters.senderAddress,
      recipientAddress: filters.recipientAddress,
      startTime,
      endTime,
      // senderIsVaultAddress: filters.senderIsVaultAddress,
      // recipientIsVaultAddress: filters.recipientIsVaultAddress,
      page: {
        current: pagination.page,
        row: pagination.pageSize
      }
      // page: pagination.page,
      // pageSize: ,
    })
    if (res.code === ApiCode.StatusOK && Array.isArray(res.data)) {
      rows.value = res.data
      const total = res.page?.rowTotal
      pagination.itemCount =
        typeof total === 'number' && Number.isFinite(total) ? total : res.data.length
    } else {
      rows.value = []
      pagination.itemCount = 0
      message.error(res.msg || t('vaultTx.loadFail'))
    }
  } finally {
    loading.value = false
  }
}

watch(
  () => vault.currentVaultId,
  () => {
    pagination.page = 1
    void load()
  }
)

watch(
  () => [filters.senderLabel, filters.recipientLabel, filters.senderAddress, filters.recipientAddress, filters.timeRange],
  () => {
    pagination.page = 1
    void load()
  }
)

onMounted(() => {
  void load()
})

function triggerFileDownload(blob: Blob, filename: string): void {
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = filename
  a.rel = 'noopener'
  a.click()
  URL.revokeObjectURL(url)
}

async function onExport(): Promise<void> {
  if (vault.currentVaultId == null) return
  exporting.value = true
  try {
    let startTime: string | null = null
    let endTime: string | null = null
    if (filters.timeRange?.[0] != null) {
      const d = new Date(filters.timeRange[0])
      const pad = (n: number) => String(n).padStart(2, '0')
      startTime = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} 00:00:00`
    }
    if (filters.timeRange?.[1] != null) {
      const d = new Date(filters.timeRange[1])
      const pad = (n: number) => String(n).padStart(2, '0')
      endTime = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} 23:59:59`
    }
    const res = await exportVaultTransactions({
      vaultId: vault.currentVaultId,
      senderLabel: filters.senderLabel,
      recipientLabel: filters.recipientLabel,
      senderAddress: filters.senderAddress,
      recipientAddress: filters.recipientAddress,
      startTime,
      endTime,
      // senderIsVaultAddress: filters.senderIsVaultAddress,
      // recipientIsVaultAddress: filters.recipientIsVaultAddress,
      page: {
        current: pagination.page,
        row: pagination.pageSize,
      },
    })
    if ('error' in res) {
      message.error(res.error || t('vaultTx.exportFail'))
      return
    }
    const name = res.filename?.trim() || `vault-transactions-${pagination.page}.xlsx`
    triggerFileDownload(res.blob, name)
    message.success(t('vaultTx.exportSuccess'))
  } catch {
    message.error(t('vaultTx.exportFail'))
  } finally {
    exporting.value = false
  }
}

function onResetFilters(): void {
  filters.senderLabel = null
  filters.recipientLabel = null
  filters.senderAddress = null
  filters.recipientAddress = null
  filters.timeRange = null
  // filters.senderIsVaultAddress = null
  // filters.recipientIsVaultAddress = null
}
</script>

<template>
  <div class="vault-list">
    <n-card class="vault-panel" :segmented="{ content: true }" size="medium">
      <template #header>
        <!-- <div class="vault-panel__header">
          <div class="vault-panel__titles">
            <h2 class="vault-panel__title">{{ t('vaultTx.cardTitle') }}</h2>
            <p class="vault-panel__desc">{{ t('vaultTx.cardSubtitle') }}</p>
          </div>
          <div v-if="vault.currentVaultId != null" class="vault-panel__meta">
            <span class="vault-panel__meta-label">{{ t('vaultTx.rowCountLabel') }}</span>
            <span class="vault-panel__meta-value">{{ pagination.itemCount }}</span>
          </div>
        </div> -->
      </template>

      <n-spin :show="loading" class="vault-panel__spin">
        <div v-if="vault.currentVaultId == null" class="vault-panel__empty-wrap">
          <n-empty size="large" :description="t('vaultTx.selectVaultHint')" />
        </div>
        <div v-else class="vault-panel__body">
          <div class="vault-panel__toolbar">
            <div class="vault-panel__filters">
              <n-input
                v-model:value="filters.senderLabel"
                :placeholder="t('vaultTx.colSenderLabel')"
                clearable
                style="width: 200px"
              />
              <n-input
                v-model:value="filters.senderAddress"
                :placeholder="t('vaultTx.colSenderAddr')"
                clearable
                style="width: 260px"
              />
              <n-input
                v-model:value="filters.recipientLabel"
                :placeholder="t('vaultTx.colRecipientLabel')"
                clearable
                style="width: 200px"
              />
              <n-input
                v-model:value="filters.recipientAddress"
                :placeholder="t('vaultTx.colRecipientAddr')"
                clearable
                style="width: 260px"
              />
              <n-date-picker
                v-model:value="filters.timeRange"
                type="daterange"
                clearable
                :start-placeholder="t('vaultTx.filterStartTime')"
                :end-placeholder="t('vaultTx.filterEndTime')"
                style="width: 420px"
              />
<!--              <n-select-->
<!--                v-model:value="filters.senderIsVaultAddress"-->
<!--                :options="boolFilterOptions"-->
<!--                :placeholder="t('vaultTx.colSenderInternal')"-->
<!--                clearable-->
<!--                style="width: 200px"-->
<!--              />-->
<!--              <n-select-->
<!--                v-model:value="filters.recipientIsVaultAddress"-->
<!--                :options="boolFilterOptions"-->
<!--                :placeholder="t('vaultTx.colRecipientInternal')"-->
<!--                clearable-->
<!--                style="width: 200px"-->
<!--              />-->
              <n-button tertiary @click="onResetFilters">{{ t('vaultTx.filterReset') }}</n-button>
            </div>
            <n-button class="vault-panel__export" type="primary" secondary :loading="exporting" @click="onExport">
              {{ t('vaultTx.export') }}
            </n-button>
          </div>
          <div class="vault-panel__table-frame">
            <n-data-table
              class="vault-panel__table"
              :columns="columns"
              :data="rows"
              :pagination="pagination"
              :bordered="true"
              striped
              bottom-bordered
              :single-line="false"
              size="medium"
              :scroll-x="tableScrollX"
              :scrollbar-props="{ trigger: 'none' }"
              :empty-description="t('vaultTx.empty')"
            />
          </div>
          <!-- 仅占位：让白卡片铺满剩余高度，表格本身不纵向拉伸 -->
          <div class="vault-panel__tail-spacer" aria-hidden="true" />
        </div>
      </n-spin>
    </n-card>
  </div>
</template>

<style scoped>
.vault-list {
  width: 100%;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.vault-panel {
  flex: 1;
  min-height: 0;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--vt-bg-elevated) !important;
  border: 1px solid var(--vt-divider) !important;
  box-shadow: var(--vt-shadow-card);
  --n-padding-top: 0;
  --n-padding-bottom: 0;
  --n-padding-left: 0;
  --n-padding-right: 0;
}

.vault-panel :deep(.n-card-header) {
  padding: 20px 22px 16px;
  border-bottom: 1px solid var(--vt-divider);
}

/* 卡片内容区铺满卡片剩余高度；内边距 15px */
.vault-panel :deep(.n-card-content) {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow-y: scroll;
  padding: 15px !important;
  box-sizing: border-box;
}

.vault-panel__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}

.vault-panel__titles {
  min-width: 0;
}

.vault-panel__title {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--vt-text);
  line-height: 1.3;
}

.vault-panel__desc {
  margin: 6px 0 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--vt-text-muted);
}

.vault-panel__meta {
  flex-shrink: 0;
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--vt-brand-soft);
  border: 1px solid rgba(79, 70, 229, 0.15);
}

.vault-panel__meta-label {
  font-size: 12px;
  font-weight: 500;
  color: var(--vt-text-muted);
}

.vault-panel__meta-value {
  font-size: 15px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--vt-brand);
}

.vault-panel__spin {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.vault-panel__spin :deep(.n-spin-content) {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.vault-panel__empty-wrap {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px 0;
}

.vault-panel__body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

.vault-panel__toolbar {
  flex-shrink: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 0 14px 10px;
  box-sizing: border-box;
}

.vault-panel__filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.vault-panel__export{
  align-self: flex-start;
}

.vault-panel__table-frame {
  flex: 0 0 auto;
  width: 100%;
  min-width: 0;
  padding: 12px 14px 10px;
  box-sizing: border-box;
  /* border: 1px solid var(--vt-border); */
  /* border-radius: 12px; */
  /* background: #fafbfc; */
  overflow-x: auto;
  overflow-y: visible;
}

.vault-panel__tail-spacer {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
}

.vault-panel__table {
  width: 100%;
  max-width: 100%;
  min-width: 0;
}

/* 表格：表头、分隔、对齐与数字字体 */
.vault-panel__table :deep(.n-data-table) {
  --n-th-padding: 11px 14px;
  --n-td-padding: 11px 14px;
}

.vault-panel__table :deep(.n-data-table-wrapper) {
  min-width: 0;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid #e5e7eb;
  background: #fff;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}

.vault-panel__table :deep(.n-data-table-base-table-header) {
  border-radius: 10px 10px 0 0;
}

.vault-panel__table :deep(.n-data-table-th) {
  text-align: center !important;
  font-weight: 600;
  font-size: 12px;
  line-height: 1.35;
  letter-spacing: 0.01em;
  color: #475569 !important;
  background: #f1f5f9 !important;
  border-color: #e2e8f0 !important;
  border-bottom: 1px solid #e2e8f0 !important;
}

.vault-panel__table :deep(.n-data-table-th__title-wrapper) {
  justify-content: center;
}

.vault-panel__table :deep(.n-data-table-td) {
  text-align: center !important;
  font-size: 13px;
  line-height: 1.45;
  color: var(--vt-text);
  border-color: #eef2f7 !important;
  vertical-align: middle;
}

.vault-panel__table :deep(.n-data-table-tr:not(.n-data-table-tr--summary):hover .n-data-table-td) {
  background: #f8fafc !important;
}

.vault-panel__table :deep(.n-data-table__pagination) {
  padding: 12px 4px 4px;
  margin-top: 2px;
  border-top: 1px solid #eef2f7;
  justify-content: flex-end;
}

.vault-panel__table :deep(.n-data-table-empty) {
  padding: 40px 16px 48px;
  background: #fff;
}

.vault-panel__table :deep(.n-data-table-empty .n-empty__description) {
  margin-top: 12px;
  font-size: 14px;
  color: var(--vt-text-muted);
}

/* 单元格内层：与表头一致居中 */
.vault-panel__table :deep(.vault-tx__cell-text),
.vault-panel__table :deep(.vault-tx__cell-num) {
  display: inline-block;
  max-width: 100%;
  vertical-align: middle;
  text-align: center;
}

.vault-panel__table :deep(.vault-tx__cell-mono) {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 12.5px;
  letter-spacing: -0.01em;
}

.vault-panel__table :deep(.vault-tx__cell-num) {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
  letter-spacing: -0.02em;
}

.vault-panel__table :deep(.vault-tx__cell-unit) {
  font-weight: 600;
  font-size: 12px;
  color: #64748b;
  text-transform: uppercase;
}

.vault-panel__table :deep(.vault-tx__cell-link) {
  color: var(--vt-brand);
  text-decoration: none;
}

.vault-panel__table :deep(.vault-tx__cell-link:hover) {
  text-decoration: underline;
}

.vault-panel__table :deep(.vault-tx__cell-status) {
  font-weight: 500;
  font-size: 12.5px;
  color: #0f172a;
}
</style>
