<!-- pages/queue/index.vue -->
<template>
  <view class="page-container bg-white">
    <TopDivBar @back="goBack" />

    <view class="tools-div">
      <view class="tool-input">
        <input
          v-model="queryForm.name"
          class="search-input"
          placeholder="请输入姓名（模糊匹配）"
        />
        <view class="tool-gap"></view>
        <input
          v-model="queryForm.idCard"
          class="search-input"
          placeholder="请输入身份证（模糊匹配）"
        />
        <view class="tool-gap"></view>
        <input
          v-model="queryForm.phone"
          class="search-input"
          placeholder="请输入手机号（模糊匹配）"
        />
      </view>
      <view class="tools-btn">
        <button
          class="btn btn-primary action-btn"
          :disabled="loading"
          @click="handleSearch"
        >
          查询
        </button>
        <view class="tool-gap"></view>
        <button
          class="btn btn-default action-btn"
          :disabled="loading"
          @click="handleReset"
        >
          重置
        </button>
      </view>
    </view>

    <view class="table-wrapper">
      <uni-table :loading="loading" border stripe emptyText="暂无更多数据">
        <uni-tr>
          <uni-th width="100" align="center">姓名</uni-th>
          <uni-th width="180" align="center">身份证</uni-th>
          <uni-th width="130" align="center">手机号</uni-th>
          <uni-th width="100" align="center">票号</uni-th>
          <uni-th width="200" align="center">核验结果</uni-th>
          <uni-th width="170" align="center">核验时间</uni-th>
          <uni-th width="100" align="center">查看照片</uni-th>
          <uni-th width="200" align="center">操作</uni-th>
        </uni-tr>
        <uni-tr v-for="item in records" :key="item.uid">
          <uni-td align="center">{{ item.name || "-" }}</uni-td>
          <uni-td align="center">{{ maskIdCard(item.idCard) }}</uni-td>
          <uni-td align="center">{{ maskPhone(item.phone) }}</uni-td>
          <uni-td align="center">{{ item.ticketId || "-" }}</uni-td>
          <uni-td align="center">
            <text class="face-resp">{{ item.baishuiResp || "-" }}</text>
          </uni-td>
          <uni-td align="center">{{ item.verifyTime || "-" }}</uni-td>
          <uni-td align="center">
            <button
              v-if="hasFaceImg(item.faceImg)"
              class="btn btn-link face-photo-btn"
              @click="openFaceImgPopup(item)"
            >
              查看照片
            </button>
            <text v-else>-</text>
          </uni-td>
          <uni-td align="center">
            <view class="row-actions">
              <button
                class="btn btn-primary report-btn"
                :disabled="!item.idCard || reportLoading"
                @click="openHealthReport(item)"
              >
                健康报告
              </button>
              <button
                class="btn btn-primary report-btn"
                :disabled="ticketLoading"
                @click="openTakeTicketPopup(item)"
              >
                取号
              </button>
              <button
                v-if="SHOW_APPOINTMENT_SIGN_IN"
                class="btn btn-default report-btn"
                @click="openAppointmentPopup(item)"
              >
                预约签到
              </button>
            </view>
          </uni-td>
        </uni-tr>
      </uni-table>
    </view>

    <view class="pagination-div">
      <text>
        共<span class="page-span">{{ total }}</span
        >条数据，每页显示<span class="page-span">{{ size }}</span
        >条
      </text>
      <view class="uni-pagination-box">
        <uni-pagination
          show-icon
          :page-size="size"
          :current="page"
          :total="total"
          @change="handlePageChange"
        />
      </view>
    </view>

    <uni-popup ref="faceImgPopup" type="center" :is-mask-click="false">
      <view class="face-img-popup">
        <view class="report-header">
          <text class="report-title">人脸照片</text>
          <view class="report-close" @click="closeFaceImgPopup">×</view>
        </view>
        <view class="face-img-body">
          <view v-if="faceImgLoading" class="report-loading"
            >照片加载中...</view
          >
          <!-- H5 / Web 使用原生 img，uni-app image 对 dataUrl/Blob 支持不稳定 -->
          <img
            v-else-if="faceImgSrc && faceImgUseNative"
            :src="faceImgSrc"
            class="face-img face-img-native"
            alt="人脸照片"
            @error="onFaceImgError"
          />
          <image
            v-else-if="faceImgSrc"
            :src="faceImgSrc"
            mode="aspectFit"
            class="face-img"
            @error="onFaceImgError"
          />
          <view v-else class="report-empty">暂无照片</view>
        </view>
      </view>
    </uni-popup>

    <uni-popup ref="reportPopup" type="center" :is-mask-click="false">
      <view class="report-popup">
        <view class="report-header">
          <text class="report-title">健康报告</text>
          <view class="report-close" @click="closeReportPopup">×</view>
        </view>
        <view class="report-body">
          <view v-if="reportLoading" class="report-loading">报告加载中...</view>
          <view v-else-if="reportUrl" class="report-frame-wrap">
            <iframe
              :src="reportUrl"
              class="report-frame"
              :style="reportFrameStyle"
              @load="updateReportFrameScale"
            ></iframe>
          </view>
          <view v-else class="report-empty">暂无报告地址</view>
        </view>
      </view>
    </uni-popup>

    <TakeTicketPopup
      ref="takeTicketPopupRef"
      @success="fetchTableData"
      @loading="(value) => (ticketLoading = value)"
    />

    <uni-popup ref="appointmentPopup" type="center">
      <view class="appoint-popup">
        <view class="popup-header">
          <text class="popup-title">预约信息</text>
          <view class="report-close" @click="closeAppointmentPopup">×</view>
        </view>
        <view class="appoint-content">
          <view class="appoint-row">
            <text class="appoint-label">姓名</text>
            <text class="appoint-value">{{ currentRow?.name || "-" }}</text>
          </view>
          <view class="appoint-row">
            <text class="appoint-label">身份证</text>
            <text class="appoint-value">{{
              maskIdCard(currentRow?.idCard)
            }}</text>
          </view>
          <view class="appoint-row">
            <text class="appoint-label">手机号</text>
            <text class="appoint-value">{{
              maskPhone(currentRow?.phone)
            }}</text>
          </view>
          <view class="appoint-row">
            <text class="appoint-label">预约时间段</text>
            <text class="appoint-value">{{
              getAppointmentTimeRange(currentRow)
            }}</text>
          </view>
        </view>
        <view class="appoint-actions">
          <button
            class="btn btn-primary report-btn"
            @click="confirmAppointmentSignIn"
          >
            签到
          </button>
        </view>
      </view>
    </uni-popup>
  </view>
</template>

<script setup>
import { getHealthReportUrl } from "@/api/index.js";
import { getFaceImage, searchTicketVerify } from "@/api/ticket.js";
import TakeTicketPopup from "@/components/TakeTicketPopup/TakeTicketPopup.vue";
import TopDivBar from "@/components/TopDivBar.vue";
import {
  extractImageBase64FromResponse,
  isWebPlatform,
  loadFaceImageDisplaySrc,
} from "@/utils/faceImage.js";
import { onHide, onLoad, onShow, onUnload } from "@dcloudio/uni-app";
import { computed, getCurrentInstance, nextTick, reactive, ref } from "vue";

// 健康报告按桌面宽度渲染后再缩放，避免 iframe 内页面走移动端布局
const REPORT_DESKTOP_WIDTH = 1280;
/** 暂时隐藏预约签到入口，恢复时改为 true */
const SHOW_APPOINTMENT_SIGN_IN = false;

const loading = ref(false);
const page = ref(1);
const size = ref(10);
const total = ref(0);
const records = ref([]);
const faceImgPopup = ref(null);
const faceImgSrc = ref("");
const faceImgLoading = ref(false);
const faceImgRevoke = ref(null);
const faceImgUseNative = ref(isWebPlatform());
const reportPopup = ref(null);
const reportUrl = ref("");
const reportLoading = ref(false);
const reportFrameScale = ref(1);
const instance = getCurrentInstance();

const reportFrameStyle = computed(() => {
  const scale = reportFrameScale.value || 1;
  return {
    width: `${REPORT_DESKTOP_WIDTH}px`,
    height: `${100 / scale}%`,
    transform: `scale(${scale})`,
    transformOrigin: "0 0",
  };
});

const updateReportFrameScale = () => {
  nextTick(() => {
    const query = uni.createSelectorQuery();
    if (instance?.proxy) {
      query.in(instance.proxy);
    }
    query
      .select(".report-body")
      .boundingClientRect((rect) => {
        if (!rect?.width) return;
        reportFrameScale.value = rect.width / REPORT_DESKTOP_WIDTH;
      })
      .exec();
  });
};
const preChecked = 0;
const takeTicketPopupRef = ref(null);
const appointmentPopup = ref(null);
const ticketLoading = ref(false);
const currentRow = ref(null);

const queryForm = reactive({
  name: "",
  idCard: "",
  phone: "",
});

const hasFaceImg = (faceImg) => Boolean(String(faceImg ?? "").trim());

const releaseFaceImgSrc = () => {
  if (typeof faceImgRevoke.value === "function") {
    faceImgRevoke.value();
  }
  faceImgRevoke.value = null;
  faceImgSrc.value = "";
};

const onFaceImgError = (event) => {
  console.log("[face-image] image 组件加载失败:", event);
  uni.showToast({
    title: "图片渲染失败",
    icon: "none",
  });
};

const openFaceImgPopup = async (row) => {
  const uid = String(row?.uid ?? "").trim();
  console.log("[face-image] 表格行 uid:", uid, "faceImg:", row?.faceImg);
  if (!uid) {
    uni.showToast({
      title: "缺少记录 uid",
      icon: "none",
    });
    return;
  }
  releaseFaceImgSrc();
  faceImgLoading.value = true;
  faceImgPopup.value?.open();
  try {
    const result = await getFaceImage(uid);
    const base64 = extractImageBase64FromResponse(result);
    console.log(
      "[face-image] imageBase64 长度:",
      base64 ? String(base64).length : 0,
    );
    if (!base64) {
      uni.showToast({
        title: "未获取到照片数据",
        icon: "none",
      });
      return;
    }
    const { src, revoke } = await loadFaceImageDisplaySrc(base64);
    faceImgRevoke.value = revoke;
    faceImgUseNative.value =
      isWebPlatform() || src.startsWith("blob:") || src.startsWith("data:");
    await nextTick();
    faceImgSrc.value = src;
    await nextTick();
    console.log(
      "[face-image] 展示地址类型:",
      src.startsWith("blob:")
        ? "blob"
        : src.startsWith("data:")
          ? "dataUrl"
          : "filePath",
      "useNativeImg:",
      faceImgUseNative.value,
    );
  } catch (error) {
    console.log("获取人脸照片失败:", error);
    uni.showToast({
      title: "获取人脸照片失败",
      icon: "none",
    });
  } finally {
    faceImgLoading.value = false;
  }
};

const closeFaceImgPopup = () => {
  faceImgPopup.value?.close();
  releaseFaceImgSrc();
  faceImgLoading.value = false;
};

const maskIdCard = (value) => {
  const text = String(value || "").trim();
  if (!text) return "-";
  if (text.length <= 8) return text;
  return `${text.slice(0, 4)}********${text.slice(-4)}`;
};

const maskPhone = (value) => {
  const text = String(value || "").trim();
  if (!text) return "-";
  if (text.length < 7) return text;
  return `${text.slice(0, 3)}****${text.slice(-4)}`;
};

const formatDateYMD = (date) => {
  const y = date.getFullYear();
  const m = String(date.getMonth() + 1).padStart(2, "0");
  const d = String(date.getDate()).padStart(2, "0");
  return `${y}-${m}-${d}`;
};

// 固定查询当天至过去三天（含当天共 4 天）
const getVerifySearchDateRange = () => {
  const endDate = new Date();
  const startDate = new Date();
  startDate.setDate(startDate.getDate() - 3);
  return {
    startDate: formatDateYMD(startDate),
    endDate: formatDateYMD(endDate),
  };
};

const fetchTableData = async () => {
  loading.value = true;
  try {
    const { startDate, endDate } = getVerifySearchDateRange();
    const result = await searchTicketVerify({
      name: queryForm.name,
      idCard: queryForm.idCard,
      phone: queryForm.phone,
      preChecked,
      startDate,
      endDate,
      page: page.value,
      size: size.value,
    });
    console.log("[queue-table] 查询参数:", {
      name: queryForm.name,
      idCard: queryForm.idCard,
      phone: queryForm.phone,
      preChecked,
      startDate,
      endDate,
      page: page.value,
      size: size.value,
    });
    console.log("[queue-table] 接口原始返回:", result);
    records.value = Array.isArray(result.records) ? result.records : [];
    total.value = Number(result.total) || 0;
    console.log("[queue-table] 表格数据 records:", records.value);
    console.log("[queue-table] 总条数 total:", total.value);
  } catch (error) {
    console.log("实名核验查询失败:", error);
  } finally {
    loading.value = false;
  }
};

const handleSearch = () => {
  page.value = 1;
  fetchTableData();
};

const handleReset = () => {
  queryForm.name = "";
  queryForm.idCard = "";
  queryForm.phone = "";
  page.value = 1;
  total.value = 0;
  records.value = [];
};

const handlePageChange = (event) => {
  page.value = event.current;
  fetchTableData();
};

const openHealthReport = async (row) => {
  if (!row?.idCard) {
    uni.showToast({
      title: "身份证号为空",
      icon: "none",
    });
    return;
  }

  reportLoading.value = true;
  reportUrl.value = "";
  reportFrameScale.value = 1;
  reportPopup.value?.open();
  nextTick(() => {
    updateReportFrameScale();
  });
  try {
    const result = await getHealthReportUrl({
      id: row.idCard,
    });
    reportUrl.value = result?.url || "";
    if (!reportUrl.value) {
      uni.showToast({
        title: "未获取到报告地址",
        icon: "none",
      });
    } else {
      nextTick(() => {
        updateReportFrameScale();
      });
    }
  } catch (error) {
    console.log("获取健康报告失败:", error);
    uni.showToast({
      title: "获取健康报告失败",
      icon: "none",
    });
  } finally {
    reportLoading.value = false;
  }
};

const closeReportPopup = () => {
  reportPopup.value?.close();
  reportUrl.value = "";
  reportFrameScale.value = 1;
};

const openTakeTicketPopup = (row) => {
  takeTicketPopupRef.value?.openWithRow(row);
};

const getAppointmentTimeRange = (row) => {
  if (!row) return "-";
  return (
    row.appointmentTimeRange ||
    row.appointmentTimeSlot ||
    row.appointmentRange ||
    "暂无预约时间段"
  );
};

const openAppointmentPopup = (row) => {
  currentRow.value = row;
  appointmentPopup.value?.open();
};

const closeAppointmentPopup = () => {
  appointmentPopup.value?.close();
};

const confirmAppointmentSignIn = () => {
  if (!currentRow.value) return;
  uni.showModal({
    title: "确认签到",
    content: `确认对 ${currentRow.value.name || "该用户"} 执行预约签到吗？`,
    success: (res) => {
      if (!res.confirm) return;
      uni.showToast({
        title: "签到成功",
        icon: "success",
      });
      closeAppointmentPopup();
    },
  });
};

const goBack = () => {
  uni.navigateBack();
};

let refreshTimer = null;

const startRefreshTimer = () => {
  stopRefreshTimer();
  refreshTimer = setInterval(() => {
    fetchTableData();
  }, 15000);
};

const stopRefreshTimer = () => {
  if (refreshTimer) {
    clearInterval(refreshTimer);
    refreshTimer = null;
  }
};

onLoad(() => {
  if (process.env.NODE_ENV === "development") {
    queryForm.name = "";
  }
});

onShow(() => {
  fetchTableData();
  startRefreshTimer();
});

onHide(() => {
  stopRefreshTimer();
});

onUnload(() => {
  stopRefreshTimer();
});
</script>

<style scoped>
.page-container {
  min-height: 100vh;
  padding-top: calc(6vh + 64px);
}

.bg-white {
  background-color: #fff;
}

.tools-div {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 20px;
}

.tool-input {
  display: flex;
  flex: 1;
  min-width: 0;
  align-items: center;
}

.tools-btn {
  display: flex;
  align-items: center;
  margin-left: 14rpx;
}

.tool-gap {
  width: 12px;
}

.search-input {
  flex: 1;
  min-width: 0;
  border: 1px solid #d1d5db;
  border-radius: 6rpx;
  background: #fff;
  padding: 0 12px;
  font-size: 14px;
  height: 36px;
  box-sizing: border-box;
}

.btn {
  min-width: 84px;
  height: 32px;
  border-radius: 4px;
  font-size: 14px;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
}

.action-btn {
  width: 84px;
}

.report-btn {
  width: 84px;
  min-width: 84px;
  height: 28px;
  font-size: 12px;
}

.btn-primary {
  background: #2563eb;
  color: #fff;
}

.btn-default {
  background: #e5e7eb;
  color: #111827;
}

.table-wrapper {
  padding: 0 20px;
}

.pagination-div {
  display: flex;
  justify-content: space-between;
  padding: 10px 20px;
  font-size: 14px;
}

.page-span {
  color: #0099ff;
  margin: 0 4px;
}

.uni-pagination-box {
  display: flex;
  justify-content: flex-end;
}

.report-popup {
  width: 96vw;
  max-width: none;
  height: 92vh;
  background: #fff;
  border-radius: 12px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.report-header {
  height: 48px;
  padding: 0 14px;
  border-bottom: 1px solid #eee;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.report-title {
  font-size: 16px;
  color: #111827;
  font-weight: 600;
}

.report-close {
  width: 28px;
  height: 28px;
  line-height: 28px;
  text-align: center;
  border-radius: 50%;
  background: #f3f4f6;
  color: #6b7280;
  font-size: 18px;
}

.report-body {
  flex: 1;
  min-height: 0;
  background: #fafafa;
  overflow: hidden;
}

.report-frame-wrap {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #fff;
}

.report-frame {
  border: none;
  background: #fff;
  display: block;
}

.report-loading,
.report-empty {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #6b7280;
  font-size: 14px;
}

.face-resp {
  font-size: 13px;
  color: #374151;
  line-height: 1.4;
}

.face-photo-btn {
  padding: 0;
  min-width: auto;
  height: auto;
  line-height: 1.2;
  font-size: 13px;
  color: #2563eb;
  background: transparent;
  border: none;
  flex-shrink: 0;
  white-space: nowrap;
}

.face-img-popup {
  width: 720rpx;
  max-width: 92vw;
  background: #fff;
  border-radius: 12px;
  overflow: hidden;
}

.face-img-body {
  padding: 12px;
  min-height: 320px;
  max-height: 70vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f9fafb;
}

.face-img {
  width: 100%;
  max-height: 65vh;
}

.face-img-native {
  display: block;
  object-fit: contain;
  min-height: 200px;
}

.row-actions {
  display: flex;
  gap: 6px;
  justify-content: center;
}

.appoint-popup {
  width: 680rpx;
  max-width: 90vw;
  background: #fff;
  border-radius: 12px;
  overflow: hidden;
}

.popup-header {
  height: 48px;
  padding: 0 14px;
  border-bottom: 1px solid #eee;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.popup-title {
  font-size: 15px;
  color: #111827;
  font-weight: 600;
}

.appoint-content {
  padding: 14px;
}

.appoint-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid #f1f5f9;
}

.appoint-label {
  color: #6b7280;
  font-size: 14px;
}

.appoint-value {
  color: #111827;
  font-size: 14px;
  text-align: right;
}

.appoint-actions {
  padding: 12px 14px 14px;
  display: flex;
  justify-content: flex-end;
}

@media (max-width: 900px) {
  .tools-div {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }

  .tool-input {
    flex-wrap: wrap;
  }

  .tool-gap {
    display: none;
  }

  .search-input {
    flex: none;
    width: 100%;
    margin-bottom: 8px;
  }

  .tools-btn {
    margin-left: 0;
    justify-content: flex-end;
  }
}
</style>
