<template>
  <PageContainer title="专家管理">
    <QueryToolbar>
      <el-input v-model="keyword" placeholder="姓名/身份证/手机号" style="width: 220px" />
      <el-button v-if="canRead" @click="load">查询</el-button>
      <el-button v-if="canImport" @click="openImportDialog">批量导入</el-button>
      <el-button v-if="canImport" @click="downloadExpertTemplate">下载模板</el-button>
      <el-button v-if="canExport" @click="handleExport">导出</el-button>
      <el-button v-if="canCreate" type="primary" @click="openExpertDrawer('create')">新增专家</el-button>
    </QueryToolbar>

    <!-- <el-form :inline="true">
      <el-form-item label="批量导入">
        <el-input
          v-model="importText"
          type="textarea"
          :rows="3"
          style="width: 460px"
          placeholder="每行：姓名|身份证|手机号|职称编码(可选)|医院编码(可选)"
        />
      </el-form-item>
      <el-form-item>
        <el-button v-if="canImport" @click="handleImport">导入</el-button>
        <el-button v-if="canExport" @click="handleExport">导出</el-button>
      </el-form-item>
    </el-form> -->

    <el-table :data="rows" class="mt-md" empty-text="暂无数据">
      <el-table-column prop="expertName" label="姓名" width="120" />
      <el-table-column prop="idNo" label="身份证" width="190" />
      <el-table-column prop="phone" label="手机号" width="130" />
      <el-table-column prop="title" label="职称" width="120" />
      <el-table-column prop="organization" label="医院" />
      <el-table-column label="操作" width="420">
        <template #default="{ row }">
          <el-button v-if="canRead" size="small" @click="openExpertDrawer('view', row.id)">查看</el-button>
          <el-button v-if="canCreate" size="small" @click="openExpertDrawer('edit', row.id)">编辑</el-button>
          <el-button v-if="canCardManage" size="small" @click="openCardListDrawer(row)">银行卡</el-button>
          <el-button v-if="canMerge" size="small" @click="openMerge(row)">合并</el-button>
        </template>
      </el-table-column>
    </el-table>
    <div class="flex-end mt-md">
      <el-pagination
        :current-page="pageNo"
        :page-size="pageSize"
        :page-sizes="[10, 20, 50, 100]"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total"
        @current-change="handlePageChange"
        @size-change="handlePageSizeChange"
      />
    </div>

    <el-drawer v-model="expertDrawerVisible" :title="expertDrawerTitle" :size="DRAWER_SIZE.md">
      <el-form ref="expertFormRef" :model="expertForm" label-position="left" :label-width="LABEL_WIDTH.md" :rules="expertFormRules">
        <el-form-item label="姓名" prop="expertName"><el-input v-model="expertForm.expertName" :disabled="expertReadonly" /></el-form-item>
        <el-form-item label="身份证" prop="idNo"><el-input v-model="expertForm.idNo" :disabled="expertReadonly || expertMode === 'edit'" /></el-form-item>
        <el-form-item label="手机号" prop="phone"><el-input v-model="expertForm.phone" :disabled="expertReadonly" /></el-form-item>
        <el-form-item label="职称" prop="titleCode">
          <el-select v-model="expertForm.titleCode" class="w-input-lg" :disabled="expertReadonly" placeholder="请选择职称">
            <el-option v-for="item in titleOptions" :key="item.dictCode" :label="item.dictName" :value="item.dictCode" />
          </el-select>
        </el-form-item>
        <el-form-item label="医院" prop="hospitalCode">
          <el-select v-model="expertForm.hospitalCode" class="w-input-lg" :disabled="expertReadonly" placeholder="请选择医院">
            <el-option v-for="item in hospitalOptions" :key="item.dictCode" :label="item.dictName" :value="item.dictCode" />
          </el-select>
        </el-form-item>
        <el-form-item label="身份证正面">
          <el-upload :auto-upload="false" :show-file-list="false" :limit="1" :disabled="expertReadonly" :on-change="onExpertIdFrontChange">
            <el-button size="small" :disabled="expertReadonly">选择文件</el-button>
          </el-upload>
          <span class="ml-sm text-secondary">选择后自动上传</span>
          <el-button v-if="expertForm.idCardFrontOssKey" size="small" class="ml-sm" @click="viewOss(expertForm.idCardFrontOssKey)">查看</el-button>
          <el-image
            v-if="expertIdFrontPreviewUrl"
            :src="expertIdFrontPreviewUrl"
            :preview-src-list="[expertIdFrontPreviewUrl]"
            preview-teleported
            class="thumbnail-sm ml-sm"
          />
        </el-form-item>
        <el-form-item label="身份证反面">
          <el-upload :auto-upload="false" :show-file-list="false" :limit="1" :disabled="expertReadonly" :on-change="onExpertIdBackChange">
            <el-button size="small" :disabled="expertReadonly">选择文件</el-button>
          </el-upload>
          <span class="ml-sm text-secondary">选择后自动上传</span>
          <el-button v-if="expertForm.idCardBackOssKey" size="small" class="ml-sm" @click="viewOss(expertForm.idCardBackOssKey)">查看</el-button>
          <el-image
            v-if="expertIdBackPreviewUrl"
            :src="expertIdBackPreviewUrl"
            :preview-src-list="[expertIdBackPreviewUrl]"
            preview-teleported
            class="thumbnail-sm ml-sm"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="expertDrawerVisible = false">关闭</el-button>
        <el-button v-if="!expertReadonly" type="primary" @click="submitExpert">保存</el-button>
      </template>
    </el-drawer>

    <el-drawer v-model="cardListDrawerVisible" title="银行卡信息" size="80%">
      <div style="margin-bottom: 12px">
        <el-button v-if="canCardManage" type="primary" @click="openCardFormDrawer('create')">新增银行卡</el-button>
      </div>
      <el-table :data="cardRows">
        <el-table-column prop="bankName" label="开户行" />
        <el-table-column prop="bankProvince" label="省份" />
        <el-table-column prop="bankCity" label="城市" />
        <el-table-column prop="bankCardNo" label="卡号" width="180"/>
        <el-table-column prop="accountName" label="账户名" />
        <el-table-column prop="isDefault" label="默认" />
        <el-table-column label="操作" width="150">
          <template #default="{ row }">
            <el-button size="small" @click="openCardFormDrawer('view', row.id)">查看</el-button>
            <el-button v-if="canCardManage" size="small" @click="openCardFormDrawer('edit', row.id)">编辑</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-drawer>

    <el-drawer v-model="cardFormDrawerVisible" :title="cardDrawerTitle" size="560px">
      <el-form ref="cardFormRef" :model="cardForm" label-position="left" :label-width="LABEL_WIDTH.md" :rules="cardFormRules">
        <el-form-item label="开户行" prop="bankName"><el-input v-model="cardForm.bankName" :disabled="cardReadonly" /></el-form-item>
        <el-form-item label="省份" prop="bankProvince"><el-input v-model="cardForm.bankProvince" :disabled="cardReadonly" /></el-form-item>
        <el-form-item label="城市" prop="bankCity"><el-input v-model="cardForm.bankCity" :disabled="cardReadonly" /></el-form-item>
        <el-form-item label="详细开户行" prop="bankBranchName"><el-input v-model="cardForm.bankBranchName" :disabled="cardReadonly" /></el-form-item>
        <el-form-item label="卡号" prop="bankCardNo"><el-input v-model="cardForm.bankCardNo" :disabled="cardReadonly" /></el-form-item>
        <el-form-item label="账户名" prop="accountName"><el-input v-model="cardForm.accountName" :disabled="cardReadonly" /></el-form-item>
        <el-form-item label="银行卡图片">
          <el-upload :auto-upload="false" :show-file-list="false" :limit="1" :disabled="cardReadonly" :on-change="onCardFrontChange">
            <el-button size="small" :disabled="cardReadonly">选择文件</el-button>
          </el-upload>
          <span class="ml-sm text-secondary">选择后自动上传</span>
          <el-button v-if="cardForm.bankCardFrontOssKey" size="small" class="ml-sm" @click="viewOss(cardForm.bankCardFrontOssKey)">查看</el-button>
          <el-image
            v-if="cardFrontPreviewUrl"
            :src="cardFrontPreviewUrl"
            :preview-src-list="[cardFrontPreviewUrl]"
            preview-teleported
            class="thumbnail-sm ml-sm"
          />
        </el-form-item>
        <el-form-item label="默认收款卡"><el-switch v-model="cardForm.isDefault" :disabled="cardReadonly" /></el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="cardFormDrawerVisible = false">关闭</el-button>
        <el-button v-if="!cardReadonly" type="primary" @click="submitCard">保存</el-button>
      </template>
    </el-drawer>

    <el-dialog v-model="mergeVisible" title="专家合并" :width="DIALOG_WIDTH.sm">
      <el-form ref="mergeFormRef" :model="mergeForm" label-position="left" :label-width="LABEL_WIDTH.md" :rules="mergeFormRules">
        <el-form-item label="目标专家ID"><el-input :model-value="selectedExpertId" readonly /></el-form-item>
        <el-form-item label="来源专家ID" prop="sourceExpertId"><el-input-number v-model="mergeForm.sourceExpertId" :min="1" /></el-form-item>
        <el-form-item label="原因" prop="reason"><el-input v-model="mergeForm.reason" /></el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="mergeVisible = false">取消</el-button>
        <el-button type="primary" @click="handleMerge">确认合并</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="expertIdOcrDialogVisible" title="身份证OCR识别结果确认" :width="DIALOG_WIDTH.md" :close-on-click-modal="false">
      <div class="lh-loose">
        <div><strong>证件面：</strong>{{ expertIdOcrData.side === "front" ? "正面" : "反面" }}</div>
        <div><strong>姓名：</strong>{{ expertIdOcrData.name || "-" }}</div>
        <div><strong>身份证号：</strong>{{ expertIdOcrData.idNo || "-" }}</div>
        <div><strong>性别：</strong>{{ expertIdOcrData.gender || "-" }}</div>
        <div><strong>民族：</strong>{{ expertIdOcrData.ethnicity || "-" }}</div>
        <div><strong>出生：</strong>{{ expertIdOcrData.birth || "-" }}</div>
        <div><strong>住址：</strong>{{ expertIdOcrData.address || "-" }}</div>
        <div><strong>签发机关：</strong>{{ expertIdOcrData.issueAuthority || "-" }}</div>
        <div><strong>签发日期：</strong>{{ expertIdOcrData.signDate || "-" }}</div>
        <div><strong>失效日期：</strong>{{ expertIdOcrData.expiryDate || "-" }}</div>
      </div>
      <template #footer>
        <el-button @click="cancelExpertIdOcrFill">取消</el-button>
        <el-button type="primary" @click="confirmExpertIdOcrFill">确认回填</el-button>
      </template>
    </el-dialog>
    <el-dialog v-model="bankCardOcrDialogVisible" title="银行卡OCR识别结果确认" :width="DIALOG_WIDTH.sm" :close-on-click-modal="false">
      <div class="lh-loose">
        <div><strong>开户行：</strong>{{ bankCardOcrData.bankName || "-" }}</div>
        <div><strong>卡号：</strong>{{ bankCardOcrData.bankCardNo || "-" }}</div>
        <div><strong>账户名：</strong>{{ bankCardOcrData.accountName || "-" }}</div>
        <div><strong>有效期：</strong>{{ bankCardOcrData.validDate || "-" }}</div>
        <div><strong>卡类型：</strong>{{ bankCardOcrData.bankCardType || "-" }}</div>
      </div>
      <template #footer>
        <el-button @click="cancelBankCardOcrFill">取消</el-button>
        <el-button type="primary" @click="confirmBankCardOcrFill">确认回填</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="importVisible" title="批量导入专家" :width="DIALOG_WIDTH.lg" destroy-on-close>
      <div class="text-secondary mb-sm">
        支持 `.csv` 或制表符文本。模板字段顺序为：
        `expertName, idNo, phone, titleCode, hospitalCode`
      </div>
      <el-upload
        :auto-upload="false"
        :show-file-list="false"
        accept=".csv,.txt"
        :on-change="handleImportFileChange"
      >
        <el-button>选择文件</el-button>
      </el-upload>
      <div v-if="importFileName" class="mt-sm text-secondary">已选择文件：{{ importFileName }}</div>
      <el-input
        v-model="importText"
        type="textarea"
        :rows="10"
        class="mt-md"
        placeholder="可直接粘贴 CSV 内容，首行需包含表头"
        @input="syncImportPreview"
      />
      <div v-if="importPreview.length" class="mt-md">
        <div class="mb-sm">预览前 {{ importPreview.length }} 行：</div>
        <el-table :data="importPreview" size="small" max-height="240">
          <el-table-column prop="expertName" label="姓名" />
          <el-table-column prop="idNo" label="身份证" />
          <el-table-column prop="phone" label="手机号" />
          <el-table-column prop="titleCode" label="职称编码" />
          <el-table-column prop="hospitalCode" label="医院编码" />
        </el-table>
      </div>
      <div v-if="lastImportResult" class="mt-md">
        <el-alert
          :title="`导入结果：成功 ${lastImportResult.success} 条，失败 ${lastImportResult.failed} 条`"
          :type="lastImportResult.failed ? 'warning' : 'success'"
          show-icon
          :closable="false"
        />
        <el-button
          v-if="lastImportResult.errors?.length"
          class="mt-sm"
          @click="downloadExpertErrorSnapshot"
        >
          下载失败快照
        </el-button>
        <el-table v-if="lastImportResult.errors?.length" :data="lastImportResult.errors" size="small" class="mt-sm" max-height="220">
          <el-table-column prop="rowNo" label="行号" width="90" />
          <el-table-column prop="identifier" label="标识" width="220" />
          <el-table-column prop="message" label="失败原因" />
        </el-table>
      </div>
      <template #footer>
        <el-button @click="importVisible = false">关闭</el-button>
        <el-button @click="downloadExpertTemplate">下载模板</el-button>
        <el-button type="primary" :loading="importLoading" @click="handleImport">开始导入</el-button>
      </template>
    </el-dialog>
  </PageContainer>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import PageContainer from "../../components/PageContainer.vue";
import QueryToolbar from "../../components/QueryToolbar.vue";
import { DRAWER_SIZE, DIALOG_WIDTH, LABEL_WIDTH } from "../../constants/ui";
import { ElMessage } from "element-plus";
import type { FormInstance, FormRules } from "element-plus";
import {
  addExpertBankCard,
  addPlatformExpertBankCard,
  createExpert,
  createPlatformExpert,
  fetchExpertUploadSign,
  exportExperts,
  exportPlatformExperts,
  fetchFilePresignDownload,
  fetchExpertBankCardDetail,
  fetchExpertBankCards,
  fetchExpertDetail,
  fetchExpertDictionaryOptions,
  fetchExperts,
  fetchPlatformExpertUploadSign,
  fetchPlatformExpertBankCardDetail,
  fetchPlatformExpertBankCards,
  fetchPlatformExpertDetail,
  recognizeIdCard,
  recognizeBankCard,
  recognizePlatformIdCard,
  recognizePlatformBankCard,
  fetchPlatformExperts,
  importExperts,
  importPlatformExperts,
  mergeExpert,
  mergePlatformExpert,
  updateExpert,
  updateExpertBankCard,
  updatePlatformExpert,
  updatePlatformExpertBankCard,
} from "../../api/modules";
import { PERMS } from "../../constants/permissions";
import { useAuthStore } from "../../stores/auth";
import { downloadCsvRows, downloadCsvTemplate, findMissingHeaders, parseDelimitedText, readTextFile } from "../../utils/batchImport";

const authStore = useAuthStore();
const isPlatform = computed(() => authStore.scope === "PLATFORM");
const canRead = computed(() => (isPlatform.value ? authStore.hasPermission(PERMS.platform.expertRead) : authStore.hasPermission(PERMS.expert.read)));
const canCreate = computed(() => (isPlatform.value ? authStore.hasPermission(PERMS.platform.expertManage) : authStore.hasPermission(PERMS.expert.create)));
const canMerge = computed(() => (isPlatform.value ? authStore.hasPermission(PERMS.platform.expertManage) : authStore.hasPermission(PERMS.expert.merge)));
const canImport = computed(() => (isPlatform.value ? authStore.hasPermission(PERMS.platform.expertManage) : authStore.hasPermission(PERMS.expert.import)));
const canExport = computed(() => (isPlatform.value ? authStore.hasPermission(PERMS.platform.expertRead) : authStore.hasPermission(PERMS.expert.export)));
const canCardManage = computed(() => (isPlatform.value ? authStore.hasPermission(PERMS.platform.expertManage) : authStore.hasPermission(PERMS.expert.cardManage)));
const canBankCardOcr = computed(() => (isPlatform.value ? authStore.hasPermission(PERMS.platform.bankCardOcr) : authStore.hasPermission(PERMS.expert.bankCardOcr)));

const keyword = ref("");
const rows = ref<any[]>([]);
const pageNo = ref(1);
const pageSize = ref(20);
const total = ref(0);
const importText = ref("");
const importVisible = ref(false);
const importLoading = ref(false);
const importFileName = ref("");
const importPreview = ref<Array<{ expertName: string; idNo: string; phone: string; titleCode: string; hospitalCode: string }>>([]);
const lastImportResult = ref<any | null>(null);
const lastImportedExperts = ref<Array<{
  expertName: string;
  idNo: string;
  phone: string;
  titleCode: string;
  hospitalCode: string;
}> | null>(null);
const titleOptions = ref<any[]>([]);
const hospitalOptions = ref<any[]>([]);

const selectedExpertId = ref<number | null>(null);
const mergeVisible = ref(false);
const mergeForm = ref({ sourceExpertId: 0, reason: "身份证重复合并" });

const expertDrawerVisible = ref(false);
const expertMode = ref<"create" | "edit" | "view">("create");
const expertForm = ref({
  expertName: "",
  idNo: "",
  phone: "",
  titleCode: "",
  hospitalCode: "",
  idCardFrontOssKey: "",
  idCardBackOssKey: "",
});
const expertFormRef = ref<FormInstance>();
const expertFormRules = ref<FormRules>({
  expertName: [{ required: true, message: "请输入姓名", trigger: "blur" }],
  idNo: [{ required: true, message: "请输入身份证", trigger: "blur" }],
  phone: [{ required: true, message: "请输入手机号", trigger: "blur" }],
  titleCode: [{ required: true, message: "请选择职称", trigger: "change" }],
  hospitalCode: [{ required: true, message: "请选择医院", trigger: "change" }],
});
const expertIdFrontFile = ref<File | null>(null);
const expertIdBackFile = ref<File | null>(null);
const expertIdFrontUploading = ref(false);
const expertIdBackUploading = ref(false);
const expertIdFrontPreviewUrl = ref("");
const expertIdBackPreviewUrl = ref("");
const expertIdOcrDialogVisible = ref(false);
const expertIdOcrPending = ref<{ side: "front" | "back"; objectKey: string } | null>(null);
const expertIdOcrData = ref({
  side: "front" as "front" | "back",
  name: "",
  idNo: "",
  gender: "",
  ethnicity: "",
  birth: "",
  address: "",
  issueAuthority: "",
  signDate: "",
  expiryDate: "",
});
const expertReadonly = computed(() => expertMode.value === "view");
const expertDrawerTitle = computed(() => (expertMode.value === "create" ? "新增专家" : expertMode.value === "edit" ? "编辑专家" : "查看专家"));

const cardListDrawerVisible = ref(false);
const cardFormDrawerVisible = ref(false);
const cardMode = ref<"create" | "edit" | "view">("create");
const selectedCardId = ref<number | null>(null);
const cardRows = ref<any[]>([]);
const cardForm = ref({
  bankName: "",
  bankProvince: "",
  bankCity: "",
  bankBranchName: "",
  bankCardNo: "",
  bankCardFrontOssKey: "",
  accountName: "",
  isDefault: false,
});
const cardFormRef = ref<FormInstance>();
const cardFormRules = ref<FormRules>({
  bankName: [{ required: true, message: "请输入开户行", trigger: "blur" }],
  bankProvince: [{ required: true, message: "请输入省份", trigger: "blur" }],
  bankCity: [{ required: true, message: "请输入城市", trigger: "blur" }],
  bankBranchName: [{ required: true, message: "请输入详细开户行", trigger: "blur" }],
  bankCardNo: [{ required: true, message: "请输入卡号", trigger: "blur" }],
  accountName: [{ required: true, message: "请输入账户名", trigger: "blur" }],
});
const mergeFormRef = ref<FormInstance>();
const mergeFormRules = ref<FormRules>({
  sourceExpertId: [{ required: true, message: "请输入来源专家ID", trigger: "blur" }],
});
const cardFrontFile = ref<File | null>(null);
const cardFrontUploading = ref(false);
const cardFrontPreviewUrl = ref("");
const bankCardOcrDialogVisible = ref(false);
const bankCardOcrData = ref({
  bankName: "",
  bankCardNo: "",
  accountName: "",
  validDate: "",
  bankCardType: "",
});
const cardReadonly = computed(() => cardMode.value === "view");
const cardDrawerTitle = computed(() => (cardMode.value === "create" ? "新增银行卡" : cardMode.value === "edit" ? "编辑银行卡" : "查看银行卡"));

const load = async () => {
  try {
    const resp = isPlatform.value
      ? await fetchPlatformExperts({ keyword: keyword.value || undefined })
      : await fetchExperts({ keyword: keyword.value || undefined, pageNo: pageNo.value, pageSize: pageSize.value });
    rows.value = resp?.data?.list || [];
    total.value = Number(resp?.data?.total || 0);
  } catch (e: any) {
    rows.value = [];
    total.value = 0;
    ElMessage.error(e?.response?.data?.message || "专家数据加载失败");
  }
};

const handlePageChange = (page: number) => {
  pageNo.value = page;
  load();
};

const handlePageSizeChange = (size: number) => {
  pageSize.value = size;
  pageNo.value = 1;
  load();
};

const openImportDialog = () => {
  importVisible.value = true;
  importText.value = "";
  importFileName.value = "";
  importPreview.value = [];
  lastImportResult.value = null;
  lastImportedExperts.value = null;
};

const downloadExpertTemplate = () => {
  downloadCsvTemplate("expert-import-template.csv", [
    "expertName",
    "idNo",
    "phone",
    "titleCode",
    "hospitalCode",
  ], [
    ["张教授", "110101199001011234", "13800138000", "CHIEF_PHYSICIAN", "BEIJING_HOSPITAL"],
  ]);
};

const handleImportFileChange = async (uploadFile: any) => {
  const file = uploadFile?.raw as File | undefined;
  if (!file) {
    return;
  }
  importFileName.value = file.name;
  importText.value = await readTextFile(file);
  syncImportPreview();
};

const parseExpertImportRows = (text: string) => {
  const rows = parseDelimitedText(text);
  if (!rows.length) {
    return [];
  }
  const [header, ...dataRows] = rows;
  const missingHeaders = findMissingHeaders(header, ["expertName", "idNo", "phone"]);
  if (missingHeaders.length) {
    return [];
  }
  const headerIndex = new Map<string, number>();
  header.forEach((name, index) => {
    headerIndex.set(String(name || "").trim(), index);
  });
  return dataRows
    .filter((row) => row.some((cell) => String(cell || "").trim().length > 0))
    .map((row) => ({
      expertName: row[headerIndex.get("expertName") ?? 0] || "",
      idNo: row[headerIndex.get("idNo") ?? 1] || "",
      phone: row[headerIndex.get("phone") ?? 2] || "",
      titleCode: row[headerIndex.get("titleCode") ?? 3] || "",
      hospitalCode: row[headerIndex.get("hospitalCode") ?? 4] || "",
    }))
    .map((item) => ({
      ...item,
      expertName: item.expertName.trim(),
      idNo: item.idNo.trim(),
      phone: item.phone.trim(),
      titleCode: item.titleCode.trim(),
      hospitalCode: item.hospitalCode.trim(),
    }));
};

const syncImportPreview = () => {
  importPreview.value = parseExpertImportRows(importText.value).slice(0, 5);
};

const validateExpertImportHeaders = (text: string) => {
  const rows = parseDelimitedText(text);
  if (!rows.length) {
    return { ok: false, missingHeaders: ["expertName", "idNo", "phone"] };
  }
  const [header] = rows;
  const missingHeaders = findMissingHeaders(header, ["expertName", "idNo", "phone"]);
  return { ok: missingHeaders.length === 0, missingHeaders };
};

const resetExpertForm = () => {
  expertForm.value = { expertName: "", idNo: "", phone: "", titleCode: "", hospitalCode: "", idCardFrontOssKey: "", idCardBackOssKey: "" };
  expertIdFrontFile.value = null;
  expertIdBackFile.value = null;
  expertIdFrontPreviewUrl.value = "";
  expertIdBackPreviewUrl.value = "";
};

const isImageFile = (nameOrKey: string) => {
  const lower = String(nameOrKey || "").toLowerCase();
  return lower.endsWith(".jpg") || lower.endsWith(".jpeg") || lower.endsWith(".png") || lower.endsWith(".webp") || lower.endsWith(".gif") || lower.endsWith(".bmp");
};

const syncExpertIdPreviewUrls = async () => {
  const frontKey = String(expertForm.value.idCardFrontOssKey || "").trim();
  const backKey = String(expertForm.value.idCardBackOssKey || "").trim();
  expertIdFrontPreviewUrl.value = "";
  expertIdBackPreviewUrl.value = "";
  if (frontKey && isImageFile(frontKey)) {
    try {
      const resp = await fetchFilePresignDownload({ objectKey: frontKey });
      expertIdFrontPreviewUrl.value = resp?.data?.signedUrl || "";
    } catch (_e) {
      expertIdFrontPreviewUrl.value = "";
    }
  }
  if (backKey && isImageFile(backKey)) {
    try {
      const resp = await fetchFilePresignDownload({ objectKey: backKey });
      expertIdBackPreviewUrl.value = resp?.data?.signedUrl || "";
    } catch (_e) {
      expertIdBackPreviewUrl.value = "";
    }
  }
};

const openExpertDrawer = async (mode: "create" | "edit" | "view", id?: number) => {
  expertMode.value = mode;
  if (mode === "create") {
    selectedExpertId.value = null;
    resetExpertForm();
    expertDrawerVisible.value = true;
    return;
  }
  if (!id) {
    return;
  }
  selectedExpertId.value = id;
  const resp = isPlatform.value ? await fetchPlatformExpertDetail(id) : await fetchExpertDetail(id);
  const data = resp?.data || {};
  expertForm.value = {
    expertName: data.expertName || "",
    idNo: data.idNo || "",
    phone: data.phone || "",
    titleCode: data.titleCode || "",
    hospitalCode: data.hospitalCode || "",
    idCardFrontOssKey: data.idCardFrontOssKey || "",
    idCardBackOssKey: data.idCardBackOssKey || "",
  };
  expertIdFrontFile.value = null;
  expertIdBackFile.value = null;
  await syncExpertIdPreviewUrls();
  expertDrawerVisible.value = true;
};

const submitExpert = async () => {
  if (!expertFormRef.value) return;
  const valid = await expertFormRef.value.validate().catch(() => false);
  if (!valid) return;

  const selectedTitle = titleOptions.value.find((item) => item.dictCode === expertForm.value.titleCode);
  const selectedHospital = hospitalOptions.value.find((item) => item.dictCode === expertForm.value.hospitalCode);
  const payload = {
    ...expertForm.value,
    title: selectedTitle?.dictName || "",
    organization: selectedHospital?.dictName || "",
  };
  if (expertMode.value === "create") {
    if (isPlatform.value) {
      await createPlatformExpert(payload);
    } else {
      await createExpert(payload);
    }
    ElMessage.success("专家创建成功");
  } else if (selectedExpertId.value) {
    if (isPlatform.value) {
      await updatePlatformExpert(selectedExpertId.value, payload);
    } else {
      await updateExpert(selectedExpertId.value, payload);
    }
    ElMessage.success("专家更新成功");
  }
  expertDrawerVisible.value = false;
  await load();
};

const openCardListDrawer = async (row: any) => {
  selectedExpertId.value = row.id;
  await loadCards();
  cardListDrawerVisible.value = true;
};

const loadCards = async () => {
  if (!selectedExpertId.value) {
    cardRows.value = [];
    return;
  }
  const resp = isPlatform.value
    ? await fetchPlatformExpertBankCards(selectedExpertId.value)
    : await fetchExpertBankCards(selectedExpertId.value);
  cardRows.value = resp?.data || [];
};

const resetCardForm = () => {
  cardForm.value = {
    bankName: "",
    bankProvince: "",
    bankCity: "",
    bankBranchName: "",
    bankCardNo: "",
    bankCardFrontOssKey: "",
    accountName: "",
    isDefault: false,
  };
  cardFrontFile.value = null;
  cardFrontPreviewUrl.value = "";
};

const openCardFormDrawer = async (mode: "create" | "edit" | "view", cardId?: number) => {
  if (!selectedExpertId.value) {
    return;
  }
  cardMode.value = mode;
  selectedCardId.value = cardId || null;
  if (mode === "create") {
    resetCardForm();
    cardFormDrawerVisible.value = true;
    return;
  }
  if (!cardId) {
    return;
  }
  const resp = isPlatform.value
    ? await fetchPlatformExpertBankCardDetail(selectedExpertId.value, cardId)
    : await fetchExpertBankCardDetail(selectedExpertId.value, cardId);
  const data = resp?.data || {};
  cardForm.value = {
    bankName: data.bankName || "",
    bankProvince: data.bankProvince || "",
    bankCity: data.bankCity || "",
    bankBranchName: data.bankBranchName || "",
    bankCardNo: data.bankCardNo || "",
    bankCardFrontOssKey: data.bankCardFrontOssKey || "",
    accountName: data.accountName || "",
    isDefault: String(data.isDefault || "N") === "Y",
  };
  cardFrontFile.value = null;
  const cardKey = String(cardForm.value.bankCardFrontOssKey || "").trim();
  cardFrontPreviewUrl.value = "";
  if (cardKey && isImageFile(cardKey)) {
    try {
      const p = await fetchFilePresignDownload({ objectKey: cardKey });
      cardFrontPreviewUrl.value = p?.data?.signedUrl || "";
    } catch (_e) {
      cardFrontPreviewUrl.value = "";
    }
  }
  cardFormDrawerVisible.value = true;
};

const onExpertIdFrontChange = async (uploadFile: any) => {
  expertIdFrontFile.value = (uploadFile?.raw as File) || null;
  if (!expertIdFrontFile.value || expertReadonly.value || expertIdFrontUploading.value) {
    return;
  }
  expertIdFrontUploading.value = true;
  try {
    await uploadExpertAsset("ID_FRONT");
  } finally {
    expertIdFrontUploading.value = false;
  }
};

const onExpertIdBackChange = async (uploadFile: any) => {
  expertIdBackFile.value = (uploadFile?.raw as File) || null;
  if (!expertIdBackFile.value || expertReadonly.value || expertIdBackUploading.value) {
    return;
  }
  expertIdBackUploading.value = true;
  try {
    await uploadExpertAsset("ID_BACK");
  } finally {
    expertIdBackUploading.value = false;
  }
};

const onCardFrontChange = async (uploadFile: any) => {
  cardFrontFile.value = (uploadFile?.raw as File) || null;
  if (!cardFrontFile.value || cardReadonly.value || cardFrontUploading.value) {
    return;
  }
  cardFrontUploading.value = true;
  try {
    await uploadExpertAsset("CARD");
  } finally {
    cardFrontUploading.value = false;
  }
};

const putToSignedUrl = async (url: string, file: File, contentType: string) => {
  const result = await fetch(url, {
    method: "PUT",
    headers: {
      "Content-Type": contentType || "application/octet-stream",
    },
    body: file,
  });
  if (!result.ok) {
    throw new Error(`上传失败: ${result.status}`);
  }
};

const uploadExpertAsset = async (target: "ID_FRONT" | "ID_BACK" | "CARD") => {
  const file =
    target === "ID_FRONT"
      ? expertIdFrontFile.value
      : target === "ID_BACK"
      ? expertIdBackFile.value
      : cardFrontFile.value;
  if (!file) {
    ElMessage.warning("请先选择文件");
    return;
  }
  const signResp = isPlatform.value
    ? await fetchPlatformExpertUploadSign({ fileName: file.name, contentType: file.type || "application/octet-stream" })
    : await fetchExpertUploadSign({ fileName: file.name, contentType: file.type || "application/octet-stream" });
  const uploadUrl = signResp?.data?.uploadUrl;
  const objectKey = signResp?.data?.objectKey;
  const contentType = signResp?.data?.contentType || file.type || "application/octet-stream";
  if (!uploadUrl || !objectKey) {
    ElMessage.error("获取上传签名失败");
    return;
  }
  await putToSignedUrl(uploadUrl, file, contentType);
  if (target === "ID_FRONT") {
    expertForm.value.idCardFrontOssKey = objectKey;
    expertIdFrontPreviewUrl.value = isImageFile(file.name) ? URL.createObjectURL(file) : "";
    expertIdFrontFile.value = null;
    await runExpertIdOcr("front", objectKey);
  } else if (target === "ID_BACK") {
    expertForm.value.idCardBackOssKey = objectKey;
    expertIdBackPreviewUrl.value = isImageFile(file.name) ? URL.createObjectURL(file) : "";
    expertIdBackFile.value = null;
    await runExpertIdOcr("back", objectKey);
  } else if (target === "CARD") {
    cardForm.value.bankCardFrontOssKey = objectKey;
    cardFrontPreviewUrl.value = isImageFile(file.name) ? URL.createObjectURL(file) : "";
    cardFrontFile.value = null;
    await runBankCardOcr(objectKey);
  }
  ElMessage.success("上传成功");
};

const runExpertIdOcr = async (side: "front" | "back", objectKey: string) => {
  try {
    const resp = isPlatform.value
      ? await recognizePlatformIdCard({ objectKey, idCardSide: side })
      : await recognizeIdCard({ objectKey, idCardSide: side });
    const n = resp?.data?.normalized || {};
    expertIdOcrPending.value = { side, objectKey };
    expertIdOcrData.value = {
      side,
      name: String(n?.name || ""),
      idNo: String(n?.idNo || ""),
      gender: String(n?.gender || ""),
      ethnicity: String(n?.ethnicity || ""),
      birth: String(n?.birth || ""),
      address: String(n?.address || ""),
      issueAuthority: String(n?.issueAuthority || ""),
      signDate: String(n?.signDate || ""),
      expiryDate: String(n?.expiryDate || ""),
    };
    expertIdOcrDialogVisible.value = true;
  } catch (e: any) {
    ElMessage.warning(e?.message || "身份证OCR识别失败");
  }
};

const confirmExpertIdOcrFill = () => {
  const side = expertIdOcrData.value.side;
  if (side === "front") {
    if (expertIdOcrData.value.name) {
      expertForm.value.expertName = expertIdOcrData.value.name;
    }
    if (expertIdOcrData.value.idNo) {
      expertForm.value.idNo = expertIdOcrData.value.idNo;
    }
  }
  expertIdOcrDialogVisible.value = false;
  ElMessage.success("已确认并回填身份证OCR结果");
};

const cancelExpertIdOcrFill = () => {
  expertIdOcrDialogVisible.value = false;
};

const runBankCardOcr = async (objectKey: string) => {
  if (!canBankCardOcr.value) {
    ElMessage.warning("当前账号无银行卡OCR权限");
    return;
  }
  try {
    const resp = isPlatform.value
      ? await recognizePlatformBankCard({ objectKey })
      : await recognizeBankCard({ objectKey });
    const n = resp?.data?.normalized || {};
    bankCardOcrData.value = {
      bankName: String(n?.bankName || ""),
      bankCardNo: String(n?.bankCardNumber || "").replace(/\s+/g, ""),
      accountName: String(n?.holderName || ""),
      validDate: String(n?.validDate || ""),
      bankCardType: String(n?.bankCardType || ""),
    };
    bankCardOcrDialogVisible.value = true;
  } catch (e: any) {
    ElMessage.warning(e?.response?.data?.message || e?.message || "银行卡OCR识别失败");
  }
};

const confirmBankCardOcrFill = () => {
  if (bankCardOcrData.value.bankName) {
    cardForm.value.bankName = bankCardOcrData.value.bankName;
  }
  if (bankCardOcrData.value.bankCardNo) {
    cardForm.value.bankCardNo = bankCardOcrData.value.bankCardNo;
  }
  if (bankCardOcrData.value.accountName) {
    cardForm.value.accountName = bankCardOcrData.value.accountName;
  }
  bankCardOcrDialogVisible.value = false;
  ElMessage.success("已确认并回填银行卡OCR结果");
};

const cancelBankCardOcrFill = () => {
  bankCardOcrDialogVisible.value = false;
};

const viewOss = async (objectKey?: string) => {
  if (!objectKey) {
    return;
  }
  const resp = await fetchFilePresignDownload({ objectKey });
  const signedUrl = resp?.data?.signedUrl;
  if (!signedUrl) {
    ElMessage.error("预览链接获取失败");
    return;
  }
  window.open(signedUrl, "_blank");
};

const submitCard = async () => {
  if (!selectedExpertId.value) return;

  if (!cardFormRef.value) return;
  const valid = await cardFormRef.value.validate().catch(() => false);
  if (!valid) return;

  if (cardMode.value === "create") {
    if (isPlatform.value) {
      await addPlatformExpertBankCard(selectedExpertId.value, cardForm.value);
    } else {
      await addExpertBankCard(selectedExpertId.value, cardForm.value);
    }
    ElMessage.success("银行卡已新增");
  } else if (selectedCardId.value) {
    if (isPlatform.value) {
      await updatePlatformExpertBankCard(selectedExpertId.value, selectedCardId.value, cardForm.value);
    } else {
      await updateExpertBankCard(selectedExpertId.value, selectedCardId.value, cardForm.value);
    }
    ElMessage.success("银行卡已更新");
  }
  cardFormDrawerVisible.value = false;
  await loadCards();
};

const handleImport = async () => {
  const headerValidation = validateExpertImportHeaders(importText.value);
  if (!headerValidation.ok) {
    ElMessage.warning(`模板表头缺失：${headerValidation.missingHeaders.join("、")}`);
    return;
  }
  const experts = parseExpertImportRows(importText.value);
  if (experts.length === 0) {
    ElMessage.warning("请先上传或粘贴导入内容");
    return;
  }
  lastImportedExperts.value = experts;
  importLoading.value = true;
  try {
    const resp = isPlatform.value ? await importPlatformExperts({ experts }) : await importExperts({ experts });
    lastImportResult.value = resp?.data || null;
    if ((resp?.data?.failed || 0) > 0) {
      ElMessage.warning(`导入完成：成功 ${resp?.data?.success || 0} 条，失败 ${resp?.data?.failed || 0} 条`);
    } else {
      ElMessage.success(`导入完成：成功 ${resp?.data?.success || 0} 条`);
    }
    await load();
  } finally {
    importLoading.value = false;
  }
};

const downloadExpertErrorSnapshot = () => {
  const errors = lastImportResult.value?.errors || [];
  const sourceRows = lastImportedExperts.value || [];
  if (!errors.length || !sourceRows.length) {
    ElMessage.warning("暂无失败快照可下载");
    return;
  }
  const rows: string[][] = [[
    "expertName",
    "idNo",
    "phone",
    "titleCode",
    "hospitalCode",
    "__error",
  ]];
  errors.forEach((error: any) => {
    const rowIndex = Number(error?.rowNo || 0) - 2;
    const item = sourceRows[rowIndex];
    if (!item) {
      return;
    }
    rows.push([
      item.expertName || "",
      item.idNo || "",
      item.phone || "",
      item.titleCode || "",
      item.hospitalCode || "",
      String(error?.message || ""),
    ]);
  });
  downloadCsvRows("expert-import-error-snapshot.csv", rows);
};

const handleExport = async () => {
  const resp = isPlatform.value ? await exportPlatformExperts() : await exportExperts();
  ElMessage.success(`导出成功，共 ${resp?.data?.total || 0} 条`);
};

const openMerge = (row: any) => {
  selectedExpertId.value = row.id;
  mergeForm.value = { sourceExpertId: 0, reason: "身份证重复合并" };
  mergeVisible.value = true;
};

const handleMerge = async () => {
  if (!selectedExpertId.value || !mergeForm.value.sourceExpertId) return;

  if (!mergeFormRef.value) return;
  const valid = await mergeFormRef.value.validate().catch(() => false);
  if (!valid) return;

  if (isPlatform.value) {
    await mergePlatformExpert(selectedExpertId.value, mergeForm.value);
  } else {
    await mergeExpert(selectedExpertId.value, mergeForm.value);
  }
  ElMessage.success("专家合并成功");
  mergeVisible.value = false;
  await load();
};

const loadDictOptions = async () => {
  const resp = await fetchExpertDictionaryOptions();
  titleOptions.value = resp?.data?.titles || [];
  hospitalOptions.value = resp?.data?.hospitals || [];
};

onMounted(async () => {
  await loadDictOptions();
  await load();
});
</script>
