<script lang="ts" setup>
/**
 * 审方卡片列表：结构化卡片 + 触底分页 + 紧急失效左边框
 */
import {
  computed,
  nextTick,
  onBeforeUnmount,
  onMounted,
  ref,
  watch,
} from 'vue';

import { Button, Empty, Space, Spin, Tag, message } from 'ant-design-vue';

import PrescriptionInfoCell from './PrescriptionInfoCell.vue';
import { getPrescriptionListApi, passApi } from '../api';

const props = defineProps<{
  formValues?: Record<string, any>;
  /** 是否显示通过/拒绝（仅待审核 Tab） */
  canAudit?: boolean;
}>();

const emit = defineEmits<{
  viewDetail: [row: Record<string, any>];
  viewSource: [id: number];
  reject: [id: number];
  openDoctor: [row: Record<string, any>];
  openPatient: [payload: { upId: number; patientName: string }];
}>();

const items = ref<any[]>([]);
const page = ref(1);
const pageCount = ref(1);
const loading = ref(false);
const loadingMore = ref(false);
const passingId = ref<number | null>(null);
/** 请求序号：只应用最后一次 list 响应，避免切 Tab/搜索竞态盖错列表 */
let requestSeq = 0;

const scrollEl = ref<HTMLElement | null>(null);
const sentinelEl = ref<HTMLElement | null>(null);
let observer: IntersectionObserver | null = null;

const hasMore = computed(() => page.value < pageCount.value);

/** 解析失效时间戳（秒） */
function resolveExpireTs(raw: number | string | null | undefined): number {
  if (raw == null || raw === '') return 0;
  if (typeof raw === 'number') {
    return raw > 1e12 ? Math.floor(raw / 1000) : raw;
  }
  const n = Number(raw);
  if (Number.isFinite(n) && n > 0) {
    return n > 1e12 ? Math.floor(n / 1000) : n;
  }
  const parsed = Date.parse(String(raw).replace(/-/g, '/'));
  return Number.isFinite(parsed) ? Math.floor(parsed / 1000) : 0;
}

/** 剩余 ≤2 小时视为紧急 */
function isUrgent(row: Record<string, any>) {
  const ts = resolveExpireTs(row.auto_expire_time);
  if (!ts) return false;
  const remain = ts - Math.floor(Date.now() / 1000);
  return remain > 0 && remain <= 2 * 3600;
}

/**
 * 拉取一页数据；reset 时清空列表
 * 用 requestSeq 丢弃过期响应，防止快速切 Tab 时旧 status 结果覆盖新 Tab
 */
async function fetchPage(targetPage: number, reset = false) {
  const seq = ++requestSeq;
  if (reset) {
    loading.value = true;
  } else {
    loadingMore.value = true;
  }
  try {
    const res = await getPrescriptionListApi({
      page: targetPage,
      pageSize: 12,
      ...(props.formValues || {}),
    });
    // 已有更新的请求在飞，丢弃本次结果
    if (seq !== requestSeq) return;
    const list = res?.items ?? [];
    page.value = res?.page ?? targetPage;
    pageCount.value = res?.page_count ?? 1;
    items.value = reset ? list : [...items.value, ...list];
  } catch (e) {
    if (seq !== requestSeq) return;
    console.error(e);
    message.error('加载审方列表失败');
  } finally {
    if (seq === requestSeq) {
      loading.value = false;
      loadingMore.value = false;
    }
  }
}

/** 搜索条件变更时重置到第 1 页并重新加载 */
async function reload() {
  page.value = 1;
  items.value = [];
  await fetchPage(1, true);
}

/**
 * 保留当前页刷新（审方成功后）：同一搜索条件重拉当前页
 * 若本页已空且不在第 1 页，则回退一页
 */
async function refreshKeepPage() {
  const current = page.value || 1;
  await fetchPage(current, true);
  if (items.value.length === 0 && current > 1) {
    page.value = current - 1;
    await fetchPage(page.value, true);
  }
}

defineExpose({ reload, refreshKeepPage });

async function loadMore() {
  if (!hasMore.value || loading.value || loadingMore.value) return;
  await fetchPage(page.value + 1, false);
}

async function handlePass(row: Record<string, any>) {
  if (passingId.value) return;
  passingId.value = row.id;
  try {
    await passApi({ id: row.id });
    message.success('通过成功');
    await refreshKeepPage();
  } catch (e) {
    console.error(e);
  } finally {
    passingId.value = null;
  }
}

function setupObserver() {
  observer?.disconnect();
  if (!sentinelEl.value) return;
  observer = new IntersectionObserver(
    (entries) => {
      if (entries.some((e) => e.isIntersecting)) {
        void loadMore();
      }
    },
    { root: scrollEl.value, rootMargin: '100px' },
  );
  observer.observe(sentinelEl.value);
}

watch(
  () => props.formValues,
  () => {
    void reload();
  },
  { deep: true },
);

onMounted(async () => {
  await reload();
  await nextTick();
  setupObserver();
});

onBeforeUnmount(() => {
  observer?.disconnect();
  observer = null;
});
</script>

<template>
  <div ref="scrollEl" class="audit-card-scroll">
    <Spin :spinning="loading">
      <div v-if="items.length" class="audit-card-grid">
        <div
          v-for="row in items"
          :key="row.id"
          class="audit-card"
          :class="{ 'audit-card--urgent': isUrgent(row) }"
        >
          <div class="audit-card__main">
            <PrescriptionInfoCell
              :row="row"
              :urgent="isUrgent(row)"
              @open-doctor="emit('openDoctor', $event)"
              @open-patient="emit('openPatient', $event)"
            />
            <div class="mt-2">
              <Tag v-if="row.status === 0" color="red">待审核</Tag>
              <Tag v-else-if="row.status === 1" color="green">已通过</Tag>
              <Tag v-else-if="row.status === 2" color="red">已拒绝</Tag>
            </div>
          </div>
          <div class="audit-card__footer">
            <Space wrap :size="8">
              <Button size="small" @click="emit('viewDetail', row)">
                查看处方
              </Button>
              <Button size="small" @click="emit('viewSource', row.id)">
                处方溯源
              </Button>
              <template v-if="canAudit !== false">
                <Button
                  size="small"
                  type="primary"
                  :loading="passingId === row.id"
                  @click="handlePass(row)"
                >
                  通过
                </Button>
                <Button
                  size="small"
                  danger
                  @click="emit('reject', row.id)"
                >
                  拒绝
                </Button>
              </template>
            </Space>
          </div>
        </div>
      </div>
      <Empty v-else-if="!loading" description="暂无待审方处方" />
    </Spin>
    <div ref="sentinelEl" class="h-8" />
    <div v-if="loadingMore" class="py-3 text-center text-xs text-gray-400">
      加载中…
    </div>
    <div
      v-else-if="items.length && !hasMore"
      class="py-3 text-center text-xs text-gray-400"
    >
      没有更多了
    </div>
  </div>
</template>

<style scoped>
.audit-card-scroll {
  height: 100%;
  overflow: auto;
  padding: 4px 2px 20px;
}
.audit-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
  gap: 16px;
}
.audit-card {
  display: flex;
  flex-direction: column;
  border: 1px solid #e5e7eb;
  border-radius: 10px;
  background: #fff;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
  overflow: hidden;
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}
.dark .audit-card {
  border-color: #334155;
  background: #0f172a;
}
.audit-card:hover {
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08);
}
.audit-card--urgent {
  border-left: 3px solid #ef4444;
}
.audit-card__main {
  flex: 1;
  padding: 14px 16px 10px;
}
.audit-card__footer {
  padding: 10px 16px 12px;
  border-top: 1px solid #f1f5f9;
  background: #fafafa;
}
.dark .audit-card__footer {
  border-top-color: #1e293b;
  background: #0b1220;
}
</style>
