<template>
  <div class="zfb-step-page">
    <header class="step-header">
      <el-steps :active="zfbStepActive" align-center finish-status="process" class="zfb-steps">
        <el-step title="第一步 完善商家信息" />
        <el-step title="第二步 完善结算信息" />
        <el-step title="第三步 提交审核" />
      </el-steps>
    </header>

    <div class="page-layout">
      <div class="main-column">
        <el-form
          ref="formRef"
          class="zfb-form"
          :model="form"
          :rules="rules"
          label-width="200px"
          require-asterisk-position="left"
          label-position="right"
        >
          <!-- 主体信息 -->
          <section id="zfb-subject" class="form-block anchor-section">
            <h2 class="section-head">
              <span class="section-bar" aria-hidden="true" />
              主体信息
            </h2>

            <el-form-item label="主体类型" prop="subjectType">
              <el-radio-group v-model="form.subjectType" class="radio-stack" @change="onSubjectTypeChange">
                <el-radio v-for="opt in subjectTypeOptions" :key="opt.value" :value="opt.value">
                  {{ opt.label }}
                </el-radio>
              </el-radio-group>
            </el-form-item>

            <el-form-item prop="licenseUrl" v-if="form.subjectType === '01'">
              <template #label>
                <span class="label-with-icon"> 营业执照 </span>
              </template>
              <div class="license-upload-wrap">
                <el-upload
                  v-model:file-list="form.licenseFileList"
                  list-type="picture-card"
                  :limit="1"
                  accept=".jpg,.jpeg,.png,.bmp,.gif,image/jpeg,image/png,image/bmp,image/gif"
                  :before-upload="beforeImageUpload"
                  :http-request="opt => handleSingleUpload(opt, 'license')"
                  :on-remove="(_f, fl) => onSingleRemove(fl, 'license')"
                >
                  <el-icon><Plus /></el-icon>
                </el-upload>
              </div>
              <div class="upload-rules">
                <p>只支持.jpg、.png格式。</p>
              </div>
            </el-form-item>

            <el-form-item label="营业执照号" prop="creditCode" v-if="form.subjectType === '01'">
              <el-input
                v-model="form.creditCode"
                placeholder="请输入统一社会信用代码"
                clearable
                maxlength="32"
                style="max-width: 480px"
              />
            </el-form-item>

            <el-form-item prop="merchantShortName" v-if="form.subjectType === '01'">
              <template #label>
                <span class="label-with-icon"> 商户简称 </span>
              </template>
              <el-input v-model="form.merchantShortName" placeholder="请输入商户简称" clearable style="max-width: 480px" />
            </el-form-item>
            <el-form-item prop="businessCategory" v-if="form.subjectType === '01'">
              <template #label>
                <span class="label-with-icon"> 经营类目 </span>
              </template>
              <el-cascader
                v-model="form.businessCategory"
                :options="categoryCascaderOptions"
                :props="categoryCascaderProps"
                placeholder="请选择经营类目"
                clearable
                filterable
                style="width: 480px"
              />
            </el-form-item>
            <!-- 
            <template v-if="form.subjectType === '02'">
              <el-form-item prop="institutionCertUrl">
                <template #label>事业单位法人证书</template>
                <div class="license-upload-wrap">
                  <el-upload
                    v-model:file-list="form.institutionCertFileList"
                    list-type="picture-card"
                    :limit="1"
                    accept=".jpg,.jpeg,.png,image/jpeg,image/png"
                    :before-upload="beforeImageUploadInstJpgPng"
                    :http-request="opt => handleSingleUpload(opt, 'institutionCert')"
                    :on-remove="(_f, fl) => onSingleRemove(fl, 'institutionCert')"
                  >
                    <el-icon><Plus /></el-icon>
                  </el-upload>
                </div>
                <div class="upload-rules">
                  <p>仅支持 jpg、png 格式。</p>
                </div>
              </el-form-item>

              <el-form-item label="事业单位法人证书编号" prop="institutionCertNumber">
                <el-input
                  v-model="form.institutionCertNumber"
                  placeholder="请输入证书编号"
                  clearable
                  maxlength="64"
                  style="max-width: 480px"
                />
              </el-form-item>

              <el-form-item prop="merchantShortName">
                <template #label>
                  <span class="label-with-icon">
                    商户简称
                    <el-tooltip placement="top" content="简称将展示给消费者，需与法人证书或品牌一致。">
                      <el-icon class="info-icon" :size="16"><InfoFilled /></el-icon>
                    </el-tooltip>
                  </span>
                </template>
                <el-input
                  v-model="form.merchantShortName"
                  placeholder="请输入商户简称"
                  clearable
                  maxlength="64"
                  show-word-limit
                  style="max-width: 480px"
                />
              </el-form-item>

              <el-form-item label="经营类目" prop="businessCategory">
                <el-cascader
                  v-model="form.businessCategory"
                  :options="categoryCascaderOptions"
                  :props="categoryCascaderProps"
                  placeholder="请选择经营类目"
                  clearable
                  filterable
                  style="width: 480px"
                />
              </el-form-item>
            </template> -->

            <!-- <template v-if="form.subjectType === '03'">
              <el-form-item prop="otherOrgCertUrl">
                <template #label>民办非企业单位登记证书</template>
                <div class="license-upload-wrap">
                  <el-upload
                    v-model:file-list="form.otherOrgCertFileList"
                    list-type="picture-card"
                    :limit="1"
                    accept=".jpg,.jpeg,.png,image/jpeg,image/png"
                    :before-upload="beforeImageUploadInstJpgPng"
                    :http-request="opt => handleSingleUpload(opt, 'otherOrgCert')"
                    :on-remove="(_f, fl) => onSingleRemove(fl, 'otherOrgCert')"
                  >
                    <el-icon><Plus /></el-icon>
                  </el-upload>
                </div>
                <div class="upload-rules">
                  <p>只支持 jpg、png 格式。</p>
                </div>
              </el-form-item>

              <el-form-item label="民办非企业单位登记证书编号" prop="otherOrgCertNumber">
                <el-input
                  v-model="form.otherOrgCertNumber"
                  placeholder="请输入证书编号"
                  clearable
                  maxlength="64"
                  style="max-width: 480px"
                />
              </el-form-item>

              <el-form-item prop="merchantShortName">
                <template #label>
                  <span class="label-with-icon">
                    商户简称
                    <el-tooltip placement="top" content="简称将展示给消费者，需与登记证书或品牌一致。">
                      <el-icon class="info-icon" :size="16"><InfoFilled /></el-icon>
                    </el-tooltip>
                  </span>
                </template>
                <el-input
                  v-model="form.merchantShortName"
                  placeholder="请输入商户简称"
                  clearable
                  maxlength="64"
                  show-word-limit
                  style="max-width: 480px"
                />
              </el-form-item>

              <el-form-item label="经营类目" prop="businessCategory">
                <el-cascader
                  v-model="form.businessCategory"
                  :options="categoryCascaderOptions"
                  :props="categoryCascaderProps"
                  placeholder="请选择经营类目"
                  clearable
                  filterable
                  style="width: 480px"
                />
              </el-form-item>
            </template> -->

            <!-- <template v-if="form.subjectType === '04'">
              <el-form-item prop="socialCertUrl">
                <template #label>社会团体法人登记证书</template>
                <div class="license-upload-wrap">
                  <el-upload
                    v-model:file-list="form.socialCertFileList"
                    list-type="picture-card"
                    :limit="1"
                    accept=".jpg,.jpeg,.png,image/jpeg,image/png"
                    :before-upload="beforeImageUploadInstJpgPng"
                    :http-request="opt => handleSingleUpload(opt, 'socialCert')"
                    :on-remove="(_f, fl) => onSingleRemove(fl, 'socialCert')"
                  >
                    <el-icon><Plus /></el-icon>
                  </el-upload>
                </div>
                <div class="upload-rules">
                  <p>只支持 jpg、png 格式。</p>
                </div>
              </el-form-item>

              <el-form-item label="社会团体法人登记证书编号" prop="socialCertNumber">
                <el-input
                  v-model="form.socialCertNumber"
                  placeholder="请输入证书编号"
                  clearable
                  maxlength="64"
                  style="max-width: 480px"
                />
              </el-form-item>

              <el-form-item prop="merchantShortName">
                <template #label>
                  <span class="label-with-icon">
                    商户简称
                    <el-tooltip placement="top" content="简称将展示给消费者，需与法人登记证书或品牌一致。">
                      <el-icon class="info-icon" :size="16"><InfoFilled /></el-icon>
                    </el-tooltip>
                  </span>
                </template>
                <el-input
                  v-model="form.merchantShortName"
                  placeholder="请输入商户简称"
                  clearable
                  maxlength="64"
                  show-word-limit
                  style="max-width: 480px"
                />
              </el-form-item>

              <el-form-item label="经营类目" prop="businessCategory">
                <el-cascader
                  v-model="form.businessCategory"
                  :options="categoryCascaderOptions"
                  :props="categoryCascaderProps"
                  placeholder="请选择经营类目"
                  clearable
                  filterable
                  style="width: 480px"
                />
              </el-form-item>
            </template> -->

            <!-- <template v-if="form.subjectType === '05'">
              <el-form-item prop="govCertUrl">
                <template #label>
                  <span class="label-wrap-multiline">党政机关批准设立文件/行政执法主体资格证</span>
                </template>
                <div class="license-upload-wrap">
                  <el-upload
                    v-model:file-list="form.govCertFileList"
                    list-type="picture-card"
                    :limit="1"
                    accept=".jpg,.jpeg,.png,image/jpeg,image/png"
                    :before-upload="beforeImageUploadInstJpgPng"
                    :http-request="opt => handleSingleUpload(opt, 'govCert')"
                    :on-remove="(_f, fl) => onSingleRemove(fl, 'govCert')"
                  >
                    <el-icon><Plus /></el-icon>
                  </el-upload>
                </div>
                <div class="upload-rules">
                  <p>只支持 jpg、png 格式。</p>
                </div>
              </el-form-item>

              <el-form-item prop="govCertNumber">
                <template #label>
                  <span class="label-wrap-multiline">党政机关批准设立文件/行政执法主体资格证编号</span>
                </template>
                <el-input
                  v-model="form.govCertNumber"
                  placeholder="请输入编号"
                  clearable
                  maxlength="128"
                  style="max-width: 480px"
                />
              </el-form-item>

              <el-form-item prop="merchantShortName">
                <template #label>
                  <span class="label-with-icon">
                    商户简称
                    <el-tooltip placement="top" content="简称将展示给消费者，需与批准文件或主体名称一致。">
                      <el-icon class="info-icon" :size="16"><InfoFilled /></el-icon>
                    </el-tooltip>
                  </span>
                </template>
                <el-input
                  v-model="form.merchantShortName"
                  placeholder="请输入商户简称"
                  clearable
                  maxlength="64"
                  show-word-limit
                  style="max-width: 480px"
                />
              </el-form-item>

              <el-form-item label="经营类目" prop="businessCategory">
                <el-cascader
                  v-model="form.businessCategory"
                  :options="categoryCascaderOptions"
                  :props="categoryCascaderProps"
                  placeholder="请选择经营类目"
                  clearable
                  filterable
                  style="width: 480px"
                />
              </el-form-item>
            </template> -->

            <!-- <template v-if="form.subjectType === '06'">
              <el-alert
                class="individual-merchant-alert"
                type="info"
                :closable="false"
                show-icon
              >
                使用当面付服务时，选择个人类型会有收款额度限制
              </el-alert>

              <el-form-item prop="idFrontUrl">
                <template #label>个人身份证</template>
                <div class="id-upload-row id-upload-row--four">
                  <div class="id-upload-cell">
                    <span class="id-side-label">上传人像面</span>
                    <el-upload
                      v-model:file-list="form.idFrontFileList"
                      list-type="picture-card"
                      :limit="1"
                      accept=".jpg,.jpeg,.png,image/jpeg,image/png"
                      :before-upload="beforeImageUploadInstJpgPng"
                      :http-request="opt => handleSingleUpload(opt, 'idFront')"
                      :on-remove="(_f, fl) => onSingleRemove(fl, 'idFront')"
                    >
                      <el-icon><Plus /></el-icon>
                    </el-upload>
                  </div>
                  <div class="id-upload-cell">
                    <span class="id-side-label">上传国徽面</span>
                    <el-upload
                      v-model:file-list="form.idBackFileList"
                      list-type="picture-card"
                      :limit="1"
                      accept=".jpg,.jpeg,.png,image/jpeg,image/png"
                      :before-upload="beforeImageUploadInstJpgPng"
                      :http-request="opt => handleSingleUpload(opt, 'idBack')"
                      :on-remove="(_f, fl) => onSingleRemove(fl, 'idBack')"
                    >
                      <el-icon><Plus /></el-icon>
                    </el-upload>
                  </div>
                </div>
                <div class="upload-rules">
                  <p>
                    说明：仅支持 jpg、png 格式。如果没有证件原件照片，可以上传证件照片复印件。
                  </p>
                </div>
              </el-form-item>

              <el-form-item label="个人身份证号码" prop="idNumber">
                <el-input v-model="form.idNumber" placeholder="请输入身份证号码" clearable style="max-width: 480px" />
              </el-form-item>

              <el-form-item prop="merchantShortName">
                <template #label>
                  <span class="label-with-icon">
                    商户简称
                    <el-tooltip placement="top" content="简称将展示给消费者，需与身份证或品牌一致。">
                      <el-icon class="info-icon" :size="16"><InfoFilled /></el-icon>
                    </el-tooltip>
                  </span>
                </template>
                <el-input
                  v-model="form.merchantShortName"
                  placeholder="请输入商户简称"
                  clearable
                  maxlength="64"
                  show-word-limit
                  style="max-width: 480px"
                />
              </el-form-item>

              <el-form-item label="经营类目" prop="businessCategory">
                <el-cascader
                  v-model="form.businessCategory"
                  :options="categoryCascaderOptions"
                  :props="categoryCascaderProps"
                  placeholder="请选择经营类目"
                  clearable
                  filterable
                  style="width: 480px"
                />
              </el-form-item>
            </template> -->

            <template v-if="form.subjectType === '07'">
              <el-form-item prop="licenseUrl">
                <template #label> 营业执照 </template>
                <div class="license-upload-wrap">
                  <el-upload
                    v-model:file-list="form.licenseFileList"
                    list-type="picture-card"
                    :limit="1"
                    accept=".jpg,.jpeg,.png,image/jpeg,image/png"
                    :before-upload="beforeImageUploadInstJpgPng"
                    :http-request="opt => handleSingleUpload(opt, 'license')"
                    :on-remove="(_f, fl) => onSingleRemove(fl, 'license')"
                  >
                    <el-icon><Plus /></el-icon>
                  </el-upload>
                </div>
                <div class="upload-rules">
                  <p>只支持 jpg、png 格式。</p>
                </div>
              </el-form-item>

              <el-form-item label="营业执照编号" prop="creditCode">
                <el-input
                  v-model="form.creditCode"
                  placeholder="请输入营业执照编号"
                  clearable
                  maxlength="32"
                  style="max-width: 480px"
                />
              </el-form-item>

              <el-form-item label="营业执照名称" prop="householdLicenseName">
                <el-input
                  v-model="form.householdLicenseName"
                  placeholder="请输入营业执照名称"
                  clearable
                  maxlength="128"
                  style="max-width: 480px"
                />
              </el-form-item>

              <el-form-item prop="merchantShortName">
                <template #label>
                  <span class="label-with-icon">
                    商户简称
                    <el-tooltip placement="top" content="简称将展示给消费者，需与营业执照或品牌一致。">
                      <el-icon class="info-icon" :size="16"><InfoFilled /></el-icon>
                    </el-tooltip>
                  </span>
                </template>
                <el-input v-model="form.merchantShortName" placeholder="请输入商户简称" clearable style="max-width: 480px" />
              </el-form-item>

              <el-form-item label="经营类目" prop="businessCategory">
                <el-cascader
                  v-model="form.businessCategory"
                  :options="categoryCascaderOptions"
                  :props="categoryCascaderProps"
                  placeholder="请选择经营类目"
                  clearable
                  filterable
                  style="width: 480px"
                />
              </el-form-item>
            </template>
          </section>

          <!-- 法人信息 -->
          <section id="zfb-legal" class="form-block anchor-section" v-if="form.subjectType === '01' || form.subjectType === '07'">
            <h2 class="section-head">
              <span class="section-bar" aria-hidden="true" />
              法人信息
            </h2>

            <el-form-item label="法定代表人/负责人证件类型" prop="legalIdType">
              <el-select v-model="form.legalIdType" placeholder="请选择" clearable style="width: 260px">
                <el-option label="居民身份证" value="id_card" />
                <el-option label="护照" value="passport" />
                <el-option label="港澳居民来往内地通行证" value="hk_macau_pass" />
                <el-option label="台湾居民来往大陆通行证" value="taiwan_pass" />
              </el-select>
            </el-form-item>

            <el-form-item prop="idFrontUrl">
              <template #label> 上传证件照片 </template>
              <div class="id-upload-row">
                <div class="id-upload-cell">
                  <div class="license-upload-wrap">
                    <el-upload
                      v-model:file-list="form.idFrontFileList"
                      list-type="picture-card"
                      :limit="1"
                      accept=".jpg,.jpeg,.png,.bmp,.gif,image/jpeg,image/png,image/bmp,image/gif"
                      :before-upload="beforeImageUpload"
                      :http-request="opt => handleSingleUpload(opt, 'idFront')"
                      :on-remove="(_f, fl) => onSingleRemove(fl, 'idFront')"
                    >
                      <div class="id-upload-trigger">
                        <el-icon><Plus /></el-icon>
                        <div class="id-side-label">上传证件正面</div>
                      </div>
                    </el-upload>
                  </div>
                </div>
                <div class="id-upload-cell">
                  <div class="license-upload-wrap">
                    <el-upload
                      v-model:file-list="form.idBackFileList"
                      list-type="picture-card"
                      :limit="1"
                      accept=".jpg,.jpeg,.png,.bmp,.gif,image/jpeg,image/png,image/bmp,image/gif"
                      :before-upload="beforeImageUpload"
                      :http-request="opt => handleSingleUpload(opt, 'idBack')"
                      :on-remove="(_f, fl) => onSingleRemove(fl, 'idBack')"
                    >
                      <div class="id-upload-trigger">
                        <el-icon><Plus /></el-icon>
                        <div class="id-side-label">上传证件反面</div>
                      </div>
                    </el-upload>
                  </div>
                </div>
              </div>
              <div class="upload-rules">
                <p>说明：仅支持.jpg、.png格式,如果没有证件原件照片，可以上传证件照片复印件。</p>
              </div>
            </el-form-item>

            <el-form-item label="证件号" prop="idNumber">
              <el-input v-model="form.idNumber" placeholder="请输入证件号码" clearable style="max-width: 480px" />
            </el-form-item>

            <el-form-item label="法定代表人/负责人姓名" prop="legalName">
              <el-input v-model="form.legalName" placeholder="请输入姓名" clearable style="max-width: 480px" />
            </el-form-item>
          </section>

          <!-- 经营信息 -->
          <section id="zfb-business" class="form-block anchor-section">
            <h2 class="section-head">
              <span class="section-bar" aria-hidden="true" />
              经营信息
            </h2>

            <el-form-item label="接入服务类型" prop="serviceTypes">
              <div class="field-stack">
                <el-checkbox-group v-model="form.serviceTypes" class="service-checks">
                  <el-checkbox v-for="s in serviceTypeOptions" :key="s.value" :label="s.value">
                    {{ s.label }}
                  </el-checkbox>
                </el-checkbox-group>
                <p class="field-tip">
                  请勾选实际售卖商品/提供服务场景(至少一项),已便为你开通所需支付权限。建议只勾选目前必须的场景，以便尽快通过入驻审核，其他支付权限可在入驻后再根据需要发起申请
                </p>
              </div>
            </el-form-item>

            <el-form-item prop="storefrontUrl" v-if="form.serviceTypes.includes('当面付')">
              <template #label> 上传门头照 </template>
              <div class="license-upload-wrap">
                <el-upload
                  v-model:file-list="form.storefrontFileList"
                  list-type="picture-card"
                  :limit="1"
                  accept=".jpg,.jpeg,.png,.bmp,.gif,image/jpeg,image/png,image/bmp,image/gif"
                  :before-upload="beforeImageUpload"
                  :http-request="opt => handleSingleUpload(opt, 'storefront')"
                  :on-remove="(_f, fl) => onSingleRemove(fl, 'storefront')"
                >
                  <el-icon><Plus /></el-icon>
                </el-upload>
              </div>
              <div class="upload-rules">
                <p>说明：仅支持jpg、png格式,图片需清晰完整，最多上传3张。</p>
              </div>
            </el-form-item>

            <el-form-item prop="interiorUrl" v-if="form.serviceTypes.includes('当面付')">
              <template #label> 上传内景照 </template>
              <div class="license-upload-wrap">
                <el-upload
                  v-model:file-list="form.interiorFileList"
                  list-type="picture-card"
                  :limit="1"
                  accept=".jpg,.jpeg,.png,.bmp,.gif,image/jpeg,image/png,image/bmp,image/gif"
                  :before-upload="beforeImageUpload"
                  :http-request="opt => handleSingleUpload(opt, 'interior')"
                  :on-remove="(_f, fl) => onSingleRemove(fl, 'interior')"
                >
                  <el-icon><Plus /></el-icon>
                </el-upload>
              </div>
              <div class="upload-rules">
                <p>说明：仅支持jpg、png格式,图片需清晰完整，最多上传3张。</p>
              </div>
            </el-form-item>

            <el-form-item label="店铺地址" prop="region" v-if="form.serviceTypes.includes('当面付')">
              <div class="address-row">
                <el-cascader
                  v-model="form.region"
                  :options="regionCascaderOptions"
                  placeholder="省 / 市"
                  filterable
                  clearable
                  style="width: 320px"
                />
                <el-input
                  v-model="form.detailAddress"
                  class="address-detail"
                  placeholder="街道、门牌号等"
                  clearable
                  maxlength="200"
                />
              </div>
            </el-form-item>

            <el-form-item label="APP名称" prop="appName" v-if="form.serviceTypes.includes('App支付')">
              <el-input
                v-model="form.appName"
                placeholder="请输入APP名称"
                clearable
                maxlength="64"
                show-word-limit
                style="max-width: 480px"
              />
            </el-form-item>

            <el-form-item label="联系人姓名" prop="contactName">
              <el-input v-model="form.contactName" placeholder="请输入联系人姓名" clearable style="max-width: 480px" />
            </el-form-item>

            <el-form-item label="联系人手机号" prop="contactPhone">
              <el-input
                v-model="form.contactPhone"
                placeholder="请输入手机号"
                clearable
                maxlength="11"
                style="max-width: 480px"
              />
            </el-form-item>

            <el-form-item label="联系人邮箱" prop="contactEmail">
              <el-input v-model="form.contactEmail" placeholder="请输入邮箱" clearable style="max-width: 480px" />
            </el-form-item>

            <el-form-item label="客服电话" prop="servicePhone">
              <el-input
                v-model="form.servicePhone"
                placeholder="请输入客服电话"
                clearable
                maxlength="20"
                style="max-width: 480px"
              />
            </el-form-item>

            <el-form-item prop="settlementAlipayAccount">
              <template #label> 签约支付宝账号 </template>
              <div class="field-stack">
                <el-input
                  v-model="form.settlementAlipayAccount"
                  placeholder="请输入用于收款的支付宝账号"
                  clearable
                  style="max-width: 480px"
                />
                <p class="field-tip">如商家无支付宝账号，请引导商家至支付宝注册。</p>
              </div>
            </el-form-item>
          </section>
        </el-form>

        <div class="footer-actions">
          <el-button type="primary" class="btn-primary-zfb" :loading="nextLoading" @click="onNext"> 下一步 </el-button>
        </div>
      </div>

      <aside class="anchor-column">
        <el-affix :offset="88">
          <div class="anchor-card">
            <el-anchor container=".el-main" :offset="72" :bound="48" direction="vertical">
              <el-anchor-link href="#zfb-subject" title="主体信息" />
              <el-anchor-link href="#zfb-legal" title="法人信息" />
              <el-anchor-link href="#zfb-business" title="经营信息" />
            </el-anchor>
          </div>
        </el-affix>
      </aside>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, reactive, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { ElMessage } from "element-plus";
import type { FormInstance, FormRules } from "element-plus";
import type { UploadRequestOptions, UploadUserFile } from "element-plus";
import { Plus, InfoFilled } from "@element-plus/icons-vue";
import { getOcrRequestByBase64 } from "@/api/modules/businessInfo";
import {
  uploadBusinessInfoImageToOss,
  uploadBusinessInfoImageWithPageOcr,
  filterOutUploadUserFileByUid,
  failBusinessInfoUploadCleanup
} from "@/utils/businessInfoImageUpload";
import { localGet, localSet } from "@/utils/index";
import cityJson from "@/assets/json/city.json";
import categoryJson from "@/views/businessInfo/category.json";

const ALIPAY_JSON_KEY = "alipayJson";
const GEEKER_USER_KEY = "geeker-user";

/** 同时勾选当面付 + App 支付时，APP 名称默认与进件 sites[0].SiteName 一致 */
const DEFAULT_ALIPAY_APP_SITE_NAME = "应用2.0签约2025092468860692";

/** 进件 externalId：16 位随机数字（0–9） */
function randomAlipayExternalId16(): string {
  const buf = new Uint8Array(16);
  crypto.getRandomValues(buf);
  let s = "";
  for (let i = 0; i < 16; i++) {
    s += String(buf[i]! % 10);
  }
  return s;
}

const formRef = ref<FormInstance>();
const nextLoading = ref(false);
const router = useRouter();
const route = useRoute();

function resolveAlipayUploadStoreId(): string | number | null {
  const q = route.query.storeId;
  if (q !== undefined && q !== null && String(q).trim() !== "") {
    return Array.isArray(q) ? q[0]! : q;
  }
  const geeker = localGet(GEEKER_USER_KEY) as { userInfo?: { storeId?: string | number | null } } | null | undefined;
  const sid = geeker?.userInfo?.storeId ?? localGet("createdId");
  if (sid === undefined || sid === null || sid === "") return null;
  return sid;
}
/** 支付宝进件步骤：0 商家信息 / 1 结算信息 / 2 提交审核 */
const zfbStepActive = ref(0);

type CategoryJsonNode = {
  code?: string;
  name?: string;
  parentCode?: string;
  parentName?: string;
  level?: number;
  display?: boolean;
  status?: string;
  sortNum?: number;
  childrenNodes?: CategoryJsonNode[];
};

type CategoryCascaderNode = { value: string; label: string; children?: CategoryCascaderNode[] };

/**
 * 二级经营类目：一级为 level=1（name/code），二级为其 childrenNodes 中 level=2 的 name/code
 */
function buildCategoryCascaderOptions(root: unknown): CategoryCascaderNode[] {
  const list = (root as { data?: { childrenNodes?: CategoryJsonNode[] } })?.data?.childrenNodes;
  if (!Array.isArray(list)) return [];
  return list
    .filter(n => n && typeof n === "object" && n.level === 1 && n.code && n.name && n.status === "VALID" && n.display !== false)
    .sort((a, b) => (a.sortNum ?? 0) - (b.sortNum ?? 0))
    .map(parent => {
      const children = (parent.childrenNodes || [])
        .filter(
          ch =>
            ch && typeof ch === "object" && ch.level === 2 && ch.code && ch.name && ch.status === "VALID" && ch.display !== false
        )
        .sort((a, b) => (a.sortNum ?? 0) - (b.sortNum ?? 0))
        .map(ch => ({
          value: String(ch.code),
          label: String(ch.name)
        }));
      return {
        value: String(parent.code),
        label: String(parent.name),
        children
      };
    })
    .filter(p => p.children && p.children.length > 0);
}

const categoryCascaderOptions = buildCategoryCascaderOptions(categoryJson);

const categoryCascaderProps = {
  value: "value",
  label: "label",
  children: "children",
  emitPath: true
};

const subjectTypeOptions = [
  { label: "企业", value: "01" },
  // { label: "事业单位", value: "02" },
  // { label: "民办非企业组织", value: "03" },
  // { label: "社会团体", value: "04" },
  // { label: "党政及国家机关", value: "05" },
  // { label: "个人商户", value: "06" },
  { label: "个体工商户", value: "07" }
];

const serviceTypeOptions = [
  { label: "当面付", value: "当面付" },
  { label: "App支付", value: "App支付" }
];

type CityJsonEntry = { name: string; adCode: string; cityCode: string };
type CityJsonRoot = { cityList: { letter: string; list: CityJsonEntry[] }[] };

const PROVINCE_ROWS: [string, string][] = [
  ["11", "北京市"],
  ["12", "天津市"],
  ["13", "河北省"],
  ["14", "山西省"],
  ["15", "内蒙古自治区"],
  ["21", "辽宁省"],
  ["22", "吉林省"],
  ["23", "黑龙江省"],
  ["31", "上海市"],
  ["32", "江苏省"],
  ["33", "浙江省"],
  ["34", "安徽省"],
  ["35", "福建省"],
  ["36", "江西省"],
  ["37", "山东省"],
  ["41", "河南省"],
  ["42", "湖北省"],
  ["43", "湖南省"],
  ["44", "广东省"],
  ["45", "广西壮族自治区"],
  ["46", "海南省"],
  ["50", "重庆市"],
  ["51", "四川省"],
  ["52", "贵州省"],
  ["53", "云南省"],
  ["54", "西藏自治区"],
  ["61", "陕西省"],
  ["62", "甘肃省"],
  ["63", "青海省"],
  ["64", "宁夏回族自治区"],
  ["65", "新疆维吾尔自治区"],
  ["71", "台湾省"],
  ["81", "香港特别行政区"],
  ["82", "澳门特别行政区"]
];
const PROVINCE_BY_PREFIX = Object.fromEntries(PROVINCE_ROWS) as Record<string, string>;
const PROVINCE_PREFIX_ORDER = PROVINCE_ROWS.map(([k]) => k);

function buildProvinceCityOptions(): {
  label: string;
  value: string;
  cities: { label: string; value: string }[];
}[] {
  const root = cityJson as CityJsonRoot;
  const flat = root.cityList.flatMap(g => g.list);
  const bucket = new Map<string, Map<string, CityJsonEntry>>();
  for (const c of flat) {
    const digits = String(c.adCode ?? "").replace(/\D/g, "");
    const code = digits.length >= 6 ? digits.slice(-6) : digits.padStart(6, "0");
    if (code.length !== 6) continue;
    const prefix = code.slice(0, 2);
    if (!PROVINCE_BY_PREFIX[prefix]) continue;
    if (!bucket.has(prefix)) bucket.set(prefix, new Map());
    bucket.get(prefix)!.set(c.adCode, c);
  }
  const out = [...bucket.entries()].map(([prefix, cityMap]) => ({
    value: prefix,
    label: PROVINCE_BY_PREFIX[prefix],
    cities: [...cityMap.values()]
      .sort((a, b) => a.name.localeCompare(b.name, "zh-CN"))
      .map(ci => ({ label: ci.name, value: ci.adCode }))
  }));
  out.sort((a, b) => {
    const ia = PROVINCE_PREFIX_ORDER.indexOf(a.value);
    const ib = PROVINCE_PREFIX_ORDER.indexOf(b.value);
    return (ia === -1 ? 999 : ia) - (ib === -1 ? 999 : ib);
  });
  return out;
}

const provinceCityOptions = buildProvinceCityOptions();

const regionCascaderOptions = computed(() =>
  provinceCityOptions.map(p => ({
    value: p.value,
    label: p.label,
    children: p.cities.map(c => ({ value: c.value, label: c.label }))
  }))
);

type UploadKind =
  | "license"
  | "idFront"
  | "idBack"
  | "storefront"
  | "interior"
  | "institutionCert"
  | "otherOrgCert"
  | "socialCert"
  | "govCert";

const form = reactive<{
  subjectType: string;
  licenseFileList: UploadUserFile[];
  licenseUrl: string;
  /** 营业执照上传接口返回的 image_id，供 alipayJson.certImage */
  licenseImageId: string;
  creditCode: string;
  householdLicenseName: string;
  merchantShortName: string;
  businessTermRange: [string, string] | undefined;
  institutionCertFileList: UploadUserFile[];
  institutionCertUrl: string;
  institutionCertNumber: string;
  otherOrgCertFileList: UploadUserFile[];
  otherOrgCertUrl: string;
  otherOrgCertNumber: string;
  socialCertFileList: UploadUserFile[];
  socialCertUrl: string;
  socialCertNumber: string;
  govCertFileList: UploadUserFile[];
  govCertUrl: string;
  govCertNumber: string;
  businessCategory: string[];
  legalIdType: string;
  idFrontFileList: UploadUserFile[];
  idFrontUrl: string;
  idBackFileList: UploadUserFile[];
  idBackUrl: string;
  idNumber: string;
  legalName: string;
  serviceTypes: string[];
  storefrontFileList: UploadUserFile[];
  storefrontUrl: string;
  /** 上传接口返回的 image_id，供 alipayJson.outDoorImages */
  storefrontImageId: string;
  interiorFileList: UploadUserFile[];
  interiorUrl: string;
  /** 上传接口返回的 image_id，供 alipayJson.inDoorImages */
  interiorImageId: string;
  institutionStorefrontFileList: UploadUserFile[];
  institutionStorefrontUrls: string[];
  institutionInteriorFileList: UploadUserFile[];
  institutionInteriorUrls: string[];
  region: string[];
  detailAddress: string;
  appName: string;
  contactName: string;
  contactPhone: string;
  contactEmail: string;
  servicePhone: string;
  settlementAlipayAccount: string;
}>({
  subjectType: "01",
  licenseFileList: [],
  licenseUrl: "",
  licenseImageId: "",
  creditCode: "",
  householdLicenseName: "",
  merchantShortName: "",
  businessTermRange: undefined,
  institutionCertFileList: [],
  institutionCertUrl: "",
  institutionCertNumber: "",
  otherOrgCertFileList: [],
  otherOrgCertUrl: "",
  otherOrgCertNumber: "",
  socialCertFileList: [],
  socialCertUrl: "",
  socialCertNumber: "",
  govCertFileList: [],
  govCertUrl: "",
  govCertNumber: "",
  businessCategory: [],
  legalIdType: "",
  idFrontFileList: [],
  idFrontUrl: "",
  idBackFileList: [],
  idBackUrl: "",
  idNumber: "",
  legalName: "",
  serviceTypes: [],
  storefrontFileList: [],
  storefrontUrl: "",
  storefrontImageId: "",
  interiorFileList: [],
  interiorUrl: "",
  interiorImageId: "",
  institutionStorefrontFileList: [],
  institutionStorefrontUrls: [],
  institutionInteriorFileList: [],
  institutionInteriorUrls: [],
  region: [],
  detailAddress: "",
  appName: "",
  contactName: "",
  contactPhone: "",
  contactEmail: "",
  servicePhone: "",
  settlementAlipayAccount: ""
});

watch(
  () => form.serviceTypes.slice().sort().join("\0"),
  () => {
    const hasFace = form.serviceTypes.includes("当面付");
    const hasApp = form.serviceTypes.includes("App支付");
    if (hasFace && hasApp && !String(form.appName || "").trim()) {
      form.appName = DEFAULT_ALIPAY_APP_SITE_NAME;
    }
  }
);

/** 用户切换到个体工商户时清空本页字段，避免企业侧已填数据带入个体户（与初始 form 一致，不改 subjectType） */
function clearZfbFormExceptSubjectType() {
  form.licenseFileList = [];
  form.licenseUrl = "";
  form.licenseImageId = "";
  form.creditCode = "";
  form.householdLicenseName = "";
  form.merchantShortName = "";
  form.businessTermRange = undefined;
  form.institutionCertFileList = [];
  form.institutionCertUrl = "";
  form.institutionCertNumber = "";
  form.otherOrgCertFileList = [];
  form.otherOrgCertUrl = "";
  form.otherOrgCertNumber = "";
  form.socialCertFileList = [];
  form.socialCertUrl = "";
  form.socialCertNumber = "";
  form.govCertFileList = [];
  form.govCertUrl = "";
  form.govCertNumber = "";
  form.businessCategory = [];
  form.legalIdType = "";
  form.idFrontFileList = [];
  form.idFrontUrl = "";
  form.idBackFileList = [];
  form.idBackUrl = "";
  form.idNumber = "";
  form.legalName = "";
  form.serviceTypes = [];
  form.storefrontFileList = [];
  form.storefrontUrl = "";
  form.storefrontImageId = "";
  form.interiorFileList = [];
  form.interiorUrl = "";
  form.interiorImageId = "";
  form.institutionStorefrontFileList = [];
  form.institutionStorefrontUrls = [];
  form.institutionInteriorFileList = [];
  form.institutionInteriorUrls = [];
  form.region = [];
  form.detailAddress = "";
  form.appName = "";
  form.contactName = "";
  form.contactPhone = "";
  form.contactEmail = "";
  form.servicePhone = "";
  form.settlementAlipayAccount = "";
}

function onSubjectTypeChange(val: string | number | boolean | undefined) {
  if (String(val ?? "") !== "07") return;
  clearZfbFormExceptSubjectType();
  nextTick(() => formRef.value?.clearValidate());
}

/** 商户端图片上传统一上限 20MB（若支付宝接口仍限 10MB，超大文件可能在服务端被拒） */
const MAX_ALIPAY_IMAGE_BYTES = 20 * 1024 * 1024;

/** 事业单位材料：仅 jpg / png（与页面说明一致） */
function beforeImageUploadInstJpgPng(file: File) {
  const name = file.name?.toLowerCase() || "";
  const okExt = /\.(jpe?g|png)$/i.test(name);
  const okMime = ["image/jpeg", "image/png"].includes(file.type);
  if (!okExt && !okMime) {
    ElMessage.error("仅支持 jpg、png 格式");
    return false;
  }
  if (file.size > MAX_ALIPAY_IMAGE_BYTES) {
    ElMessage.error("文件大小不能超过 20M");
    return false;
  }
  return true;
}

function beforeImageUpload(file: File) {
  const name = file.name?.toLowerCase() || "";
  const okExt = /\.(jpe?g|png|bmp|gif)$/i.test(name);
  const okMime = ["image/jpeg", "image/png", "image/bmp", "image/gif"].includes(file.type);
  if (!okExt && !okMime) {
    ElMessage.error("图片只支持 JPG、BMP、PNG、GIF 格式");
    return false;
  }
  if (file.size > MAX_ALIPAY_IMAGE_BYTES) {
    ElMessage.error("文件大小不能超过 20M");
    return false;
  }
  return true;
}

/** 解析 image_type：扩展名 3～16 字符，jpeg 归一为 jpg */
function resolveAlipayImageType(file: File): string | null {
  const name = file.name || "";
  const extMatch = /\.([a-zA-Z0-9]{1,16})$/i.exec(name);
  let ext = extMatch ? extMatch[1].toLowerCase() : "";
  if (ext === "jpeg") ext = "jpg";
  if (ext && ext.length >= 3 && ext.length <= 16) return ext;
  const mime = file.type;
  if (mime === "image/jpeg") return "jpg";
  if (mime === "image/png") return "png";
  if (mime === "image/gif") return "gif";
  if (mime === "image/bmp") return "bmp";
  return null;
}

/** 解析支付宝/通用上传返回；兼容 data 为 JSON 字符串（直付通 ant_merchant_expand_indirect_image_upload_response） */
function parseMediaUploadResult(res: any): { fileUrl: string; mediaId: string; errMsg: string } {
  const errMsg = String(res?.msg ?? "").trim();
  let payload = res?.data;
  if (payload === undefined) payload = res;

  if (typeof payload === "string") {
    const s = payload.trim();
    if (/^https?:\/\//i.test(s)) return { fileUrl: s, mediaId: "", errMsg };
    if ((s.startsWith("{") || s.startsWith("[")) && s.length > 1) {
      try {
        payload = JSON.parse(s);
      } catch {
        if (s) return { fileUrl: "", mediaId: s, errMsg };
        return { fileUrl: "", mediaId: "", errMsg };
      }
    } else if (s) {
      return { fileUrl: "", mediaId: s, errMsg };
    } else {
      return { fileUrl: "", mediaId: "", errMsg };
    }
  }

  if (!payload || typeof payload !== "object") {
    return { fileUrl: "", mediaId: "", errMsg };
  }

  let body: any = payload;
  if ("data" in payload && payload.data !== undefined) {
    if (typeof payload.data === "string") {
      const inner = payload.data.trim();
      if (/^https?:\/\//i.test(inner)) return { fileUrl: inner, mediaId: "", errMsg };
      if ((inner.startsWith("{") || inner.startsWith("[")) && inner.length > 1) {
        try {
          body = JSON.parse(inner);
        } catch {
          if (inner) return { fileUrl: "", mediaId: inner, errMsg };
          body = payload;
        }
      } else if (inner) {
        return { fileUrl: "", mediaId: inner, errMsg };
      }
    } else if (payload.data && typeof payload.data === "object") {
      body = payload.data;
    }
  }

  if (body && typeof body === "object" && "data" in body && body.data !== undefined) {
    if (typeof body.data === "string") {
      const inner = body.data.trim();
      if (/^https?:\/\//i.test(inner)) return { fileUrl: inner, mediaId: "", errMsg };
      if ((inner.startsWith("{") || inner.startsWith("[")) && inner.length > 1) {
        try {
          body = JSON.parse(inner);
        } catch {
          if (inner) return { fileUrl: "", mediaId: inner, errMsg };
        }
      } else if (inner) {
        return { fileUrl: "", mediaId: inner, errMsg };
      }
    } else if (body.data && typeof body.data === "object") {
      body = body.data;
    }
  }

  const antUpload =
    body?.ant_merchant_expand_indirect_image_upload_response ?? body?.antMerchantExpandIndirectImageUploadResponse;

  const fileUrl = String(
    body?.url ?? body?.fileUrl ?? body?.imageUrl ?? body?.image_url ?? body?.picUrl ?? body?.ossUrl ?? body?.file_path ?? ""
  ).trim();
  const mediaId = String(
    antUpload?.image_id ??
      antUpload?.imageId ??
      body?.image_id ??
      body?.imageId ??
      body?.resource_id ??
      body?.resourceId ??
      body?.media_id ??
      body?.mediaId ??
      body?.outBizNo ??
      body?.pictureId ??
      ""
  ).trim();
  return { fileUrl, mediaId, errMsg };
}

/** 与支付宝上传返回常见的 object / 文件名一致 */
const ALIPAY_UPLOAD_IMAGE_FILE_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.(jpe?g|png)$/i;

function extractAlipayFilenameFromImageUrl(url: string): string {
  const s = String(url || "").trim();
  if (!s || !/^https?:\/\//i.test(s)) return "";
  try {
    const seg = decodeURIComponent(new URL(s).pathname.split("/").filter(Boolean).pop() || "");
    if (ALIPAY_UPLOAD_IMAGE_FILE_RE.test(seg) || /\.(jpe?g|png)$/i.test(seg)) return seg;
  } catch {
    /* ignore */
  }
  return "";
}

/** 深度遍历响应，取 image_id 等字段（兼容多层 data / 字段名差异） */
function deepPickAlipayImageId(node: any, depth = 0): string {
  if (depth > 14 || node === null || node === undefined) return "";
  if (typeof node === "string") {
    const t = node.trim();
    if (ALIPAY_UPLOAD_IMAGE_FILE_RE.test(t)) return t;
    if (t.startsWith("{") && t.includes("image")) {
      try {
        return deepPickAlipayImageId(JSON.parse(t), depth + 1);
      } catch {
        return "";
      }
    }
    return "";
  }
  if (typeof node !== "object") return "";
  if (Array.isArray(node)) {
    for (const x of node) {
      const r = deepPickAlipayImageId(x, depth + 1);
      if (r) return r;
    }
    return "";
  }
  const keys = ["image_id", "imageId", "ImageId", "fileName", "file_name", "objectName", "object_name", "key", "picName"];
  for (const k of keys) {
    if (!(k in node) || node[k] == null) continue;
    const v = String(node[k]).trim();
    if (!v) continue;
    if (/^https?:\/\//i.test(v)) {
      const fromUrl = extractAlipayFilenameFromImageUrl(v);
      if (fromUrl) return fromUrl;
    } else {
      const base = v.split(/[/\\]/).pop() || v;
      if (base) return base.trim();
    }
  }
  for (const v of Object.values(node)) {
    const r = deepPickAlipayImageId(v, depth + 1);
    if (r) return r;
  }
  return "";
}

/** 上传成功后得到进件用图片名：扁平解析 → 深度查找 → 从返回的图片 URL 截取 */
function resolveAlipayUploadImageId(res: any, fileUrl: string, mediaId: string): string {
  let id = String(mediaId || "").trim();
  if (id) return id.split(/[/\\]/).pop() || id;
  id = deepPickAlipayImageId(res);
  if (id) return id.split(/[/\\]/).pop() || id;
  return extractAlipayFilenameFromImageUrl(fileUrl);
}

function isAlipayUploadHttpSuccess(res: any): boolean {
  return res?.code === 200 || res?.code === "200";
}

/** 与 subjectInfo：营业执照 OCR 响应解析 */
function pickBusinessLicenseOcrFields(res: any) {
  const raw = res?.data ?? res;
  let node: any = raw;
  if (node && typeof node === "object" && "data" in node && node.data !== undefined) {
    node = node.data;
  }
  const item = Array.isArray(node) ? node[0] : node;
  if (!item || typeof item !== "object") {
    return { creditCode: "", companyName: "", legalPerson: "" };
  }
  return {
    creditCode: String(item.creditCode ?? item.credit_code ?? "").trim(),
    companyName: String(item.companyName ?? item.company_name ?? "").trim(),
    legalPerson: String(item.legalPerson ?? item.legal_person ?? "").trim()
  };
}

/** 事业单位法人证书 OCR：证书编号、单位名称（回显商户简称） */
function pickInstitutionCertOcrFields(res: any): { certNumber: string; orgName: string } {
  const base = pickBusinessLicenseOcrFields(res);
  const raw = res?.data ?? res;
  let node: any = raw;
  if (node && typeof node === "object" && "data" in node && node.data !== undefined) {
    node = node.data;
  }
  const item = Array.isArray(node) ? node[0] : node;
  let certNumber = base.creditCode;
  let orgName = base.companyName;
  if (item && typeof item === "object") {
    if (!certNumber) {
      certNumber = String(
        item.certNumber ??
          item.certificateNumber ??
          item.cert_no ??
          item.certificateNo ??
          item.registrationNumber ??
          item.registration_no ??
          ""
      ).trim();
    }
    if (!orgName) {
      orgName = String(item.companyName ?? item.company_name ?? item.orgName ?? item.unitName ?? item.name ?? "").trim();
    }
  }
  return { certNumber, orgName };
}

/** 身份证有效期 → YYYY-MM-DD（与 subjectInfo 一致） */
function splitIdCardValidPeriod(raw: string): { begin: string; end: string } {
  const s = (raw || "").trim();
  if (!s) return { begin: "", end: "" };
  if (/长期|长期有效/.test(s)) return { begin: "", end: "长期" };
  const norm = s
    .replace(/年|月|日/g, ".")
    .replace(/\.+/g, ".")
    .trim();
  const parts = norm.split(/[-至~～]/);
  const normOne = (p: string) => {
    const m = p.trim().match(/(\d{4})\D*(\d{1,2})\D*(\d{1,2})/);
    if (m) return `${m[1]}-${m[2].padStart(2, "0")}-${m[3].padStart(2, "0")}`;
    return p.trim();
  };
  if (parts.length >= 2) {
    return { begin: normOne(parts[0]), end: normOne(parts[1]) };
  }
  return { begin: "", end: "" };
}

/** 与 subjectInfo：身份证 OCR 响应解析 */
function pickIdCardPortraitOcrFields(res: any): {
  name: string;
  idNumber: string;
  idCardAddress: string;
  cardPeriodBegin: string;
  cardPeriodEnd: string;
} {
  const raw = res?.data ?? res;
  let node: any = raw;
  if (node && typeof node === "object" && "data" in node && node.data !== undefined) {
    node = node.data;
  }
  const arr = Array.isArray(node) ? node : [node];
  const item = arr[0];
  const item2 = arr[1];
  if (!item || typeof item !== "object") {
    return { name: "", idNumber: "", idCardAddress: "", cardPeriodBegin: "", cardPeriodEnd: "" };
  }
  let name = String(item.name ?? item.userName ?? "").trim();
  let idNumber = String(item.idNumber ?? item.id_number ?? item.idCard ?? item.id_card ?? "").trim();
  const faceData = item.face?.data || item2?.face?.data;
  const backData = item.back?.data || item2?.back?.data;
  if (faceData && typeof faceData === "object") {
    if (!name) name = String(faceData.name ?? "").trim();
    if (!idNumber) idNumber = String(faceData.idNumber ?? faceData.id_number ?? "").trim();
  }
  let idCardAddress = "";
  if (backData && typeof backData === "object") {
    idCardAddress = String(backData.address ?? backData.registeredAddress ?? backData.issueAuthority ?? "").trim();
  }
  if (faceData && typeof faceData === "object" && !idCardAddress) {
    idCardAddress = String(faceData.address ?? "").trim();
  }
  const faceKv = item.face?.prism_keyValueInfo || item2?.face?.prism_keyValueInfo;
  if (Array.isArray(faceKv)) {
    for (const row of faceKv) {
      if (row?.key === "name" && row?.value && !name) name = String(row.value).trim();
      if (row?.key === "idNumber" && row?.value && !idNumber) idNumber = String(row.value).trim();
      if (row?.key === "address" && row?.value && !idCardAddress) {
        idCardAddress = String(row.value).trim();
      }
    }
  }
  const backKv = item.back?.prism_keyValueInfo || item2?.back?.prism_keyValueInfo;
  let validPeriodFromKv = "";
  if (Array.isArray(backKv)) {
    for (const row of backKv) {
      if (row?.key === "address" && row?.value && !idCardAddress) {
        idCardAddress = String(row.value).trim();
      }
      if (row?.value) {
        const keyRaw = String(row.key || "");
        if (/有效期限|有效期|失效日期|签发日期|validPeriod|validDate|valid_period/i.test(keyRaw)) {
          const v = String(row.value).trim();
          if (v && !validPeriodFromKv) validPeriodFromKv = v;
        }
      }
    }
  }
  let vp = String(
    (backData && (backData.validPeriod ?? backData.validDate)) ||
      (faceData && (faceData.validPeriod ?? faceData.validDate)) ||
      (item && (item.validPeriod ?? item.validDate)) ||
      (item2 && (item2.validPeriod ?? item2.validDate)) ||
      ""
  ).trim();
  if (!vp && validPeriodFromKv) vp = validPeriodFromKv;
  const { begin: cardPeriodBegin, end: cardPeriodEnd } = splitIdCardValidPeriod(vp);
  return { name, idNumber, idCardAddress, cardPeriodBegin, cardPeriodEnd };
}

function isOcrSuccess(res: any): boolean {
  return res?.code === 200 || res?.code === "200";
}

/** 上传成功后按类型调用 OCR 并写入表单（与 subjectInfo 请求体一致：imageFile + ocrType） */
async function runOcrAfterZfbUpload(kind: UploadKind, file: File) {
  if (kind === "license") {
    const formData = new FormData();
    formData.append("imageFile", file, file.name || "license.jpg");
    formData.append("ocrType", "BUSINESS_LICENSE");
    const res: any = await getOcrRequestByBase64(formData);
    if (!isOcrSuccess(res)) {
      throw new Error(String(res?.msg || "营业执照识别未通过，请核对照片清晰度"));
    }
    const fields = pickBusinessLicenseOcrFields(res);
    if (fields.creditCode) form.creditCode = fields.creditCode;
    if (form.subjectType === "07") {
      if (fields.companyName) {
        form.householdLicenseName = fields.companyName;
        form.merchantShortName = fields.companyName;
      }
    } else {
      if (fields.companyName) form.merchantShortName = fields.companyName;
      if (fields.legalPerson) form.legalName = fields.legalPerson;
    }
    return;
  }
  if (kind === "institutionCert") {
    const formData = new FormData();
    formData.append("imageFile", file, file.name || "institution-cert.jpg");
    formData.append("ocrType", "BUSINESS_LICENSE");
    const res: any = await getOcrRequestByBase64(formData);
    if (!isOcrSuccess(res)) {
      throw new Error(String(res?.msg || "事业单位法人证书识别未通过，请核对照片清晰度"));
    }
    const f = pickInstitutionCertOcrFields(res);
    if (f.certNumber) form.institutionCertNumber = f.certNumber;
    if (f.orgName) form.merchantShortName = f.orgName;
    return;
  }
  if (kind === "idFront") {
    const formData = new FormData();
    formData.append("imageFile", file, file.name || "id-portrait.jpg");
    formData.append("ocrType", "ID_CARD");
    const res: any = await getOcrRequestByBase64(formData);
    if (!isOcrSuccess(res)) {
      throw new Error(String(res?.msg || "身份证人像面识别未通过，请核对照片清晰度"));
    }
    const f = pickIdCardPortraitOcrFields(res);
    if (f.name) form.legalName = f.name;
    if (f.idNumber) form.idNumber = f.idNumber;
    if (f.cardPeriodBegin && f.cardPeriodEnd) {
      form.businessTermRange = [f.cardPeriodBegin, f.cardPeriodEnd];
    }
    return;
  }
  if (kind === "idBack") {
    const formData = new FormData();
    formData.append("imageFile", file, file.name || "id-emblem.jpg");
    formData.append("ocrType", "ID_CARD");
    const res: any = await getOcrRequestByBase64(formData);
    if (!isOcrSuccess(res)) {
      throw new Error(String(res?.msg || "身份证国徽面识别未通过，请核对照片清晰度"));
    }
    const f = pickIdCardPortraitOcrFields(res);
    if (f.cardPeriodBegin && f.cardPeriodEnd) {
      form.businessTermRange = [f.cardPeriodBegin, f.cardPeriodEnd];
    } else if (!f.cardPeriodBegin && !f.cardPeriodEnd) {
      throw new Error("未识别到有效期限，请确认国徽面照片清晰完整");
    }
  }
}

function urlFieldFor(kind: UploadKind): keyof typeof form {
  const map: Record<UploadKind, keyof typeof form> = {
    license: "licenseUrl",
    idFront: "idFrontUrl",
    idBack: "idBackUrl",
    storefront: "storefrontUrl",
    interior: "interiorUrl",
    institutionCert: "institutionCertUrl",
    otherOrgCert: "otherOrgCertUrl",
    socialCert: "socialCertUrl",
    govCert: "govCertUrl"
  };
  return map[kind];
}

function fileListForUploadKind(kind: UploadKind): UploadUserFile[] {
  const map: Record<UploadKind, UploadUserFile[]> = {
    license: form.licenseFileList,
    idFront: form.idFrontFileList,
    idBack: form.idBackFileList,
    storefront: form.storefrontFileList,
    interior: form.interiorFileList,
    institutionCert: form.institutionCertFileList,
    otherOrgCert: form.otherOrgCertFileList,
    socialCert: form.socialCertFileList,
    govCert: form.govCertFileList
  };
  return map[kind] ?? [];
}

function setFileListForUploadKind(kind: UploadKind, list: UploadUserFile[]) {
  if (kind === "license") form.licenseFileList = list;
  else if (kind === "idFront") form.idFrontFileList = list;
  else if (kind === "idBack") form.idBackFileList = list;
  else if (kind === "storefront") form.storefrontFileList = list;
  else if (kind === "interior") form.interiorFileList = list;
  else if (kind === "institutionCert") form.institutionCertFileList = list;
  else if (kind === "otherOrgCert") form.otherOrgCertFileList = list;
  else if (kind === "socialCert") form.socialCertFileList = list;
  else if (kind === "govCert") form.govCertFileList = list;
}

async function handleSingleUpload(options: UploadRequestOptions, kind: UploadKind) {
  const uploadFileItem = options.file as UploadUserFile;
  const uid = uploadFileItem.uid;
  const raw = uploadFileItem.raw || uploadFileItem;
  const file = raw instanceof File ? raw : null;
  const field = urlFieldFor(kind);

  if (!file) {
    setFileListForUploadKind(kind, filterOutUploadUserFileByUid(fileListForUploadKind(kind), uid));
    options.onError(new Error("无效文件") as any);
    return;
  }

  uploadFileItem.status = "uploading";
  try {
    if (file.size > MAX_ALIPAY_IMAGE_BYTES) {
      setFileListForUploadKind(kind, filterOutUploadUserFileByUid(fileListForUploadKind(kind), uid));
      ElMessage.error("文件大小不能超过 20M");
      options.onError(new Error("文件大小不能超过 20M") as any);
      return;
    }
    const needOcr = kind === "license" || kind === "idFront" || kind === "idBack" || kind === "institutionCert";
    const { fileUrl } = needOcr
      ? await uploadBusinessInfoImageWithPageOcr(file, f => runOcrAfterZfbUpload(kind, f), {
          showUploadOverlay: true
        })
      : await uploadBusinessInfoImageToOss(file, { showUploadOverlay: true });
    const resolvedImageId = extractAlipayFilenameFromImageUrl(fileUrl) || fileUrl;

    if (needOcr) {
      nextTick(() => {
        const f = formRef.value;
        if (!f) return;
        if (kind === "license") {
          f.validateField("creditCode").catch(() => {});
          f.validateField("merchantShortName").catch(() => {});
          if (form.subjectType === "07") {
            f.validateField("householdLicenseName").catch(() => {});
          } else {
            f.validateField("legalName").catch(() => {});
          }
        } else if (kind === "institutionCert") {
          f.validateField("institutionCertNumber").catch(() => {});
          f.validateField("merchantShortName").catch(() => {});
        } else if (kind === "idFront") {
          f.validateField("legalName").catch(() => {});
          f.validateField("idNumber").catch(() => {});
          f.validateField("businessTermRange").catch(() => {});
        } else if (kind === "idBack") {
          f.validateField("businessTermRange").catch(() => {});
        }
      });
    }

    uploadFileItem.status = "success";
    uploadFileItem.url = fileUrl;
    uploadFileItem.response = { media_id: resolvedImageId, url: fileUrl };
    (form as any)[field] = fileUrl;
    if (kind === "storefront") {
      form.storefrontImageId = resolvedImageId;
    }
    if (kind === "interior") {
      form.interiorImageId = resolvedImageId;
    }
    if (kind === "license") {
      form.licenseImageId = resolvedImageId;
    }
    options.onSuccess({ url: fileUrl } as any);
  } catch (err) {
    failBusinessInfoUploadCleanup({
      fileList: fileListForUploadKind(kind),
      setFileList: list => setFileListForUploadKind(kind, list),
      uid,
      onClear: () => clearZfbUploadFieldsForKind(kind),
      error: err
    });
    options.onError(err as any);
  }
  formRef.value?.validateField(field as string).catch(() => {});
}

function clearZfbUploadFieldsForKind(kind: UploadKind) {
  const field = urlFieldFor(kind);
  (form as any)[field] = "";
  if (kind === "storefront") form.storefrontImageId = "";
  if (kind === "interior") form.interiorImageId = "";
  if (kind === "license") form.licenseImageId = "";
}

function onSingleRemove(fileList: UploadUserFile[], kind: UploadKind) {
  const field = urlFieldFor(kind);
  if (!fileList.length) {
    (form as any)[field] = "";
    if (kind === "storefront") form.storefrontImageId = "";
    if (kind === "interior") form.interiorImageId = "";
    if (kind === "license") form.licenseImageId = "";
  } else {
    const first = fileList[0] as UploadUserFile & {
      url?: string;
      response?: { url?: string; media_id?: string };
    };
    (form as any)[field] = first?.url || first?.response?.url || "";
    if (kind === "storefront") {
      form.storefrontImageId = String(first?.response?.media_id || "").trim();
    }
    if (kind === "interior") {
      form.interiorImageId = String(first?.response?.media_id || "").trim();
    }
    if (kind === "license") {
      form.licenseImageId = String(first?.response?.media_id || "").trim();
    }
  }
  formRef.value?.validateField(field as string).catch(() => {});
}

/** alipayJson.service 仅传接入类型的 value（当面付 / App支付），不把 face_to_face、app 等内部码传给接口 */
function serviceValuesForAlipayPayload(selected: string[]): string[] {
  const codeToValue: Record<string, string> = {
    face_to_face: "当面付",
    app: "App支付"
  };
  const allowed = new Set(serviceTypeOptions.map(o => o.value));
  const out: string[] = [];
  const seen = new Set<string>();
  for (const s of selected) {
    const v = codeToValue[s] ?? (allowed.has(s) ? s : "");
    if (v && !seen.has(v)) {
      seen.add(v);
      out.push(v);
    }
  }
  return out;
}

/** 店铺地址写入 alipayJson；行政区划码由省前缀、市 adCode 推导（仅省/市二级时 DistrictCode 与 CityCode 相同） */
function buildBusinessAddressForAlipayJson():
  | {
      address: string;
      districtCode: string;
      cityCode: string;
      provinceCode: string;
    }
  | undefined {
  const region = form.region;
  if (!Array.isArray(region) || region.length < 2) return undefined;
  const provPrefix = String(region[0] ?? "").replace(/\D/g, "");
  const cityAd = String(region[1] ?? "").replace(/\D/g, "");
  if (!provPrefix || cityAd.length < 6) return undefined;

  const prov = provinceCityOptions.find(p => p.value === region[0]);
  const provinceName = prov?.label ?? "";
  const cityName = prov?.cities.find(c => c.value === region[1])?.label ?? "";
  const detail = String(form.detailAddress || "").trim();
  const address = `${provinceName}${cityName}${detail}`.trim();

  const provinceCode = provPrefix.padEnd(6, "0").slice(0, 6);
  const cityCode = cityAd.padStart(6, "0").slice(0, 6);
  const districtCode = cityCode;

  return { address, districtCode, cityCode, provinceCode };
}

/** 进件用图片标识：支付宝 image_id 或 OSS 地址中的文件名（*.jpg / *.png） */
function alipayImageIdFromUploadOnly(imageIdField: string): string {
  const s = String(imageIdField || "").trim();
  if (!s) return "";
  if (/^https?:\/\//i.test(s)) {
    return extractAlipayFilenameFromImageUrl(s) || "";
  }
  const lower = s.toLowerCase();
  if (lower.endsWith(".jpg") || lower.endsWith(".jpeg") || lower.endsWith(".png")) return s;
  return "";
}

/** 进件接口要求数组：有图为单元素数组，无图为 [] */
function alipayImageIdArrayForPayload(imageIdField: string): string[] {
  const id = alipayImageIdFromUploadOnly(imageIdField);
  return id ? [id] : [];
}

/** 从 localStorage 读取的 alipayJson 可能是对象或历史字符串 */
function normalizeAlipayJsonFromStorage(raw: unknown): Record<string, unknown> | null {
  if (raw == null || raw === "") return null;
  if (typeof raw === "string") {
    try {
      const o = JSON.parse(raw) as unknown;
      return typeof o === "object" && o !== null && !Array.isArray(o) ? (o as Record<string, unknown>) : null;
    } catch {
      return null;
    }
  }
  if (typeof raw === "object" && !Array.isArray(raw)) return raw as Record<string, unknown>;
  return null;
}

function findCategoryPathByMcc(mcc: string): string[] | undefined {
  const m = String(mcc || "").trim();
  if (!m) return undefined;
  for (const p of categoryCascaderOptions) {
    const ch = p.children?.find(c => c.value === m);
    if (ch) return [p.value, ch.value];
  }
  return undefined;
}

function firstImageIdFromAlipayField(val: unknown): string {
  if (Array.isArray(val) && val.length > 0) return String(val[0] ?? "").trim();
  if (typeof val === "string") return val.trim();
  return "";
}

/** 将 businessAddress 反填为省市区 cascader + 详细地址（与 buildBusinessAddressForAlipayJson 对称） */
function regionAndDetailFromBusinessAddress(ba: unknown): { region: string[]; detailAddress: string } | undefined {
  if (!ba || typeof ba !== "object") return undefined;
  const o = ba as Record<string, unknown>;
  const provinceCode = String(o.provinceCode ?? "").replace(/\D/g, "");
  const cityCode = String(o.cityCode ?? "").replace(/\D/g, "");
  const address = String(o.address ?? "").trim();
  if (provinceCode.length < 2 || cityCode.length < 6) return undefined;
  const prefix = provinceCode.slice(0, 2);
  const prov = provinceCityOptions.find(p => p.value === prefix);
  if (!prov) return undefined;
  const normCity = cityCode.padStart(6, "0").slice(0, 6);
  const city = prov.cities.find(c => {
    const ad = String(c.value ?? "").replace(/\D/g, "");
    const tail = ad.length >= 6 ? ad.slice(-6) : ad;
    return tail.padStart(6, "0") === normCity;
  });
  if (!city) return undefined;
  let detail = address;
  const prefixStr = `${prov.label}${city.label}`;
  if (address.startsWith(prefixStr)) detail = address.slice(prefixStr.length).trim();
  return { region: [prefix, city.value], detailAddress: detail };
}

/** alipayJson.service 为「当面付」「App支付」等；兼容旧内部码 */
function serviceTypesFromAlipayService(val: unknown): string[] {
  const allowed = new Set(serviceTypeOptions.map(o => o.value));
  const legacy: Record<string, string> = {
    face_to_face: "当面付",
    app: "App支付"
  };
  const arr = Array.isArray(val) ? val : typeof val === "string" && val.trim() ? [val] : [];
  const out: string[] = [];
  const seen = new Set<string>();
  for (const item of arr) {
    let s = String(item ?? "").trim();
    if (s.toLowerCase() === "app 支付") s = "App支付";
    const mapped = legacy[s] ?? s;
    if (mapped && allowed.has(mapped) && !seen.has(mapped)) {
      seen.add(mapped);
      out.push(mapped);
    }
  }
  return out;
}

/** 进入本页时把缓存中的 alipayJson 写回第一步表单 */
function applyAlipayJsonCacheToForm(data: Record<string, unknown>) {
  const st = String(data.merchantType ?? "").trim();
  if (st) form.subjectType = st;

  const name = String(data.name ?? data.aliasName ?? "").trim();
  if (name) form.merchantShortName = name;

  const mcc = String(data.mcc ?? "").trim();
  const path = findCategoryPathByMcc(mcc);
  if (path) form.businessCategory = path;

  const certNo = String(data.certNo ?? "").trim();
  if (certNo) form.creditCode = certNo;

  const certImage = String(data.certImage ?? "").trim();
  if (certImage) form.licenseImageId = certImage;

  const legalName = String(data.legalName ?? "").trim();
  if (legalName) form.legalName = legalName;

  const legalCertNo = String(data.legalCertNo ?? "").trim();
  if (legalCertNo) form.idNumber = legalCertNo;

  const certName = String(data.certName ?? "").trim();
  if (certName && form.subjectType === "07") form.householdLicenseName = certName;

  const alipayId = String(data.alipayLogonId ?? data.bindingAlipayLogonId ?? data.BindingAlipayLogonId ?? "").trim();
  if (alipayId) form.settlementAlipayAccount = alipayId;

  const ci = data.contactInfos;
  if (Array.isArray(ci) && ci.length > 0) {
    const c0 = ci[0] as Record<string, unknown>;
    const cn = String(c0?.name ?? "").trim();
    const cm = String(c0?.mobile ?? "").trim();
    if (cn) form.contactName = cn;
    if (cm) form.contactPhone = cm;
  }

  const svc = serviceTypesFromAlipayService(data.service);
  if (svc.length) form.serviceTypes = svc;

  const inId = firstImageIdFromAlipayField(data.inDoorImages);
  if (inId) form.interiorImageId = inId;

  const outId = firstImageIdFromAlipayField(data.outDoorImages);
  if (outId) form.storefrontImageId = outId;

  const ba = regionAndDetailFromBusinessAddress(data.businessAddress);
  if (ba) {
    form.region = ba.region;
    form.detailAddress = ba.detailAddress;
  }

  const sites = data.sites;
  if (Array.isArray(sites) && sites.length > 0) {
    const s0 = sites[0] as Record<string, unknown>;
    const sn = String(s0?.siteName ?? s0?.siteName ?? "").trim();
    if (sn) form.appName = sn;
  }
}

/** 下一步写入 localStorage，供后续支付宝进件等使用 */
function buildAlipayJsonPayload() {
  const mcc =
    Array.isArray(form.businessCategory) && form.businessCategory.length >= 2
      ? form.businessCategory[1]
      : Array.isArray(form.businessCategory) && form.businessCategory.length === 1
        ? form.businessCategory[0]
        : "";
  const businessAddress = buildBusinessAddressForAlipayJson();
  const certName = form.subjectType === "07" ? String(form.householdLicenseName || "").trim() : "";
  const alipayLogonIdVal = String(form.settlementAlipayAccount || "").trim();
  const hasFaceToFace = form.serviceTypes.includes("当面付");
  const hasAppPay = form.serviceTypes.includes("App支付");
  const siteNameForPayload = String(form.appName || "").trim() || DEFAULT_ALIPAY_APP_SITE_NAME;
  return {
    type: 0,
    externalId: randomAlipayExternalId16(),
    name: form.merchantShortName,
    aliasName: form.merchantShortName,
    merchantType: form.subjectType,
    mcc,
    certNo: form.creditCode,
    certType: 201,
    certImage: alipayImageIdFromUploadOnly(form.licenseImageId),
    legalName: form.legalName,
    legalCertNo: form.idNumber,
    certName,
    alipayLogonId: alipayLogonIdVal,
    contactInfos: [
      {
        name: String(form.contactName || "").trim(),
        mobile: String(form.contactPhone || "").trim()
      }
    ],
    service: serviceValuesForAlipayPayload(form.serviceTypes),
    inDoorImages: alipayImageIdArrayForPayload(form.interiorImageId),
    outDoorImages: alipayImageIdArrayForPayload(form.storefrontImageId),
    ...(businessAddress ? { businessAddress } : {}),
    ...(hasFaceToFace && hasAppPay
      ? {
          sites: [{ siteType: "02", siteName: siteNameForPayload }]
        }
      : {})
  };
}

onMounted(async () => {
  const cached = normalizeAlipayJsonFromStorage(localGet(ALIPAY_JSON_KEY));
  if (cached) applyAlipayJsonCacheToForm(cached);
  await nextTick();
  formRef.value?.clearValidate();
});

const rules: FormRules = {
  subjectType: [{ required: true, message: "请选择主体类型", trigger: "change" }],
  serviceTypes: [
    {
      type: "array",
      required: true,
      min: 1,
      message: "请选择接入服务类型",
      trigger: "change"
    }
  ],
  licenseUrl: [
    {
      validator: (_r, _v, cb) => {
        if (form.subjectType !== "01" && form.subjectType !== "07") return cb();
        if (!String(form.licenseUrl || "").trim()) cb(new Error("请上传营业执照"));
        else cb();
      },
      trigger: "change"
    }
  ],
  creditCode: [
    {
      validator: (_r, _v, cb) => {
        if (form.subjectType !== "01" && form.subjectType !== "07") return cb();
        const v = String(form.creditCode || "").trim();
        if (!v) {
          cb(new Error(form.subjectType === "07" ? "请输入营业执照编号" : "请输入营业执照号"));
        } else if (v.length < 15 || v.length > 32) cb(new Error("长度一般为 18 位统一社会信用代码"));
        else cb();
      },
      trigger: "blur"
    }
  ],
  householdLicenseName: [
    {
      validator: (_r, _v, cb) => {
        if (form.subjectType !== "07") return cb();
        if (!String(form.householdLicenseName || "").trim()) cb(new Error("请输入营业执照名称"));
        else cb();
      },
      trigger: "blur"
    }
  ],
  merchantShortName: [
    {
      validator: (_r, _v, cb) => {
        if (!["01", "02", "03", "04", "05", "06", "07"].includes(form.subjectType)) return cb();
        if (!String(form.merchantShortName || "").trim()) cb(new Error("请输入商户简称"));
        else cb();
      },
      trigger: "blur"
    }
  ],
  institutionCertUrl: [
    {
      validator: (_r, _v, cb) => {
        if (form.subjectType !== "institution") return cb();
        if (!String(form.institutionCertUrl || "").trim()) cb(new Error("请上传事业单位法人证书"));
        else cb();
      },
      trigger: "change"
    }
  ],
  institutionCertNumber: [
    {
      validator: (_r, _v, cb) => {
        if (form.subjectType !== "institution") return cb();
        if (!String(form.institutionCertNumber || "").trim()) cb(new Error("请输入事业单位法人证书编号"));
        else cb();
      },
      trigger: "blur"
    }
  ],
  otherOrgCertUrl: [
    {
      validator: (_r, _v, cb) => {
        if (form.subjectType !== "other_org") return cb();
        if (!String(form.otherOrgCertUrl || "").trim()) cb(new Error("请上传民办非企业单位登记证书"));
        else cb();
      },
      trigger: "change"
    }
  ],
  otherOrgCertNumber: [
    {
      validator: (_r, _v, cb) => {
        if (form.subjectType !== "other_org") return cb();
        if (!String(form.otherOrgCertNumber || "").trim()) cb(new Error("请输入民办非企业单位登记证书编号"));
        else cb();
      },
      trigger: "blur"
    }
  ],
  socialCertUrl: [
    {
      validator: (_r, _v, cb) => {
        if (form.subjectType !== "social") return cb();
        if (!String(form.socialCertUrl || "").trim()) cb(new Error("请上传社会团体法人登记证书"));
        else cb();
      },
      trigger: "change"
    }
  ],
  socialCertNumber: [
    {
      validator: (_r, _v, cb) => {
        if (form.subjectType !== "social") return cb();
        if (!String(form.socialCertNumber || "").trim()) cb(new Error("请输入社会团体法人登记证书编号"));
        else cb();
      },
      trigger: "blur"
    }
  ],
  govCertUrl: [
    {
      validator: (_r, _v, cb) => {
        if (form.subjectType !== "gov") return cb();
        if (!String(form.govCertUrl || "").trim()) {
          cb(new Error("请上传党政机关批准设立文件/行政执法主体资格证"));
        } else cb();
      },
      trigger: "change"
    }
  ],
  govCertNumber: [
    {
      validator: (_r, _v, cb) => {
        if (form.subjectType !== "gov") return cb();
        if (!String(form.govCertNumber || "").trim()) {
          cb(new Error("请输入党政机关批准设立文件/行政执法主体资格证编号"));
        } else cb();
      },
      trigger: "blur"
    }
  ],
  businessCategory: [
    {
      validator: (_r, _v, cb) => {
        if (!["01", "02", "03", "04", "05", "06", "07"].includes(form.subjectType)) return cb();
        const bc = form.businessCategory;
        if (!Array.isArray(bc) || bc.length < 2 || !String(bc[0] || "").trim() || !String(bc[1] || "").trim()) {
          cb(new Error("请选择经营类目（需选择到二级分类）"));
        } else cb();
      },
      trigger: "change"
    }
  ],
  legalIdType: [
    {
      validator: (_r, _v, cb) => {
        if (!["01", "institution", "other_org", "social"].includes(form.subjectType)) return cb();
        if (!String(form.legalIdType || "").trim()) cb(new Error("请选择证件类型"));
        else cb();
      },
      trigger: "change"
    }
  ],
  idFrontUrl: [
    {
      validator: (_r, _v, cb) => {
        if (!["01", "institution", "other_org", "social", "individual_merchant"].includes(form.subjectType)) return cb();
        if (!String(form.idFrontUrl || "").trim()) {
          cb(new Error(form.subjectType === "individual_merchant" ? "请上传身份证人像面" : "请上传证件正面"));
        } else cb();
      },
      trigger: "change"
    }
  ],
  idBackUrl: [
    {
      validator: (_r, _v, cb) => {
        if (!["01", "institution", "other_org", "social", "individual_merchant"].includes(form.subjectType)) return cb();
        if (!String(form.idBackUrl || "").trim()) {
          cb(new Error(form.subjectType === "individual_merchant" ? "请上传身份证国徽面" : "请上传证件反面"));
        } else cb();
      },
      trigger: "change"
    }
  ],
  idNumber: [
    {
      validator: (_r, _v, cb) => {
        if (!["01", "institution", "other_org", "social", "individual_merchant"].includes(form.subjectType)) return cb();
        if (!String(form.idNumber || "").trim()) {
          cb(new Error(form.subjectType === "individual_merchant" ? "请输入个人身份证号码" : "请输入证件号"));
        } else cb();
      },
      trigger: "blur"
    }
  ],
  legalName: [
    {
      validator: (_r, _v, cb) => {
        if (!["01", "institution", "other_org", "social"].includes(form.subjectType)) return cb();
        if (!String(form.legalName || "").trim()) cb(new Error("请输入法定代表人/负责人姓名"));
        else cb();
      },
      trigger: "blur"
    }
  ],
  storefrontUrl: [{ required: true, message: "请上传门头照", trigger: "change" }],
  interiorUrl: [{ required: true, message: "请上传内景照", trigger: "change" }],
  region: [{ type: "array", required: true, min: 2, message: "请选择省、市", trigger: "change" }],
  detailAddress: [{ required: true, message: "请输入详细地址", trigger: "blur" }],
  contactName: [{ required: true, message: "请输入联系人姓名", trigger: "blur" }],
  contactPhone: [
    { required: true, message: "请输入联系人手机号", trigger: "blur" },
    { pattern: /^1\d{10}$/, message: "请输入有效手机号", trigger: "blur" }
  ],
  contactEmail: [
    { required: true, message: "请输入联系人邮箱", trigger: "blur" },
    { type: "email", message: "邮箱格式不正确", trigger: "blur" }
  ],
  servicePhone: [
    { required: true, message: "请输入客服电话", trigger: "blur" },
    { pattern: /^[\d\-+\s]{5,20}$/, message: "请输入有效电话号码", trigger: "blur" }
  ],
  settlementAlipayAccount: [{ required: true, message: "请输入签约支付宝账号", trigger: "blur" }]
};

async function onNext() {
  if (!formRef.value) return;
  nextLoading.value = true;
  try {
    localSet(ALIPAY_JSON_KEY, buildAlipayJsonPayload());
    await router.push({ path: "/businessInfo/zfbIndexTwo", query: { ...route.query } });
  } catch {
    ElMessage.warning("请完善必填信息");
  } finally {
    nextLoading.value = false;
  }
}
</script>

<style scoped lang="scss">
$zfb-blue: #1677ff;
.zfb-step-page {
  box-sizing: border-box;
  min-height: 100%;
  padding: 24px 24px 48px;
  margin: 0 auto;
  background: #ffffff;
}
.step-header {
  margin-right: -24px;
  margin-bottom: 28px;
  margin-left: -24px;
}
.zfb-steps {
  width: 100%;
  margin: 0;
}
.step-header :deep(.zfb-steps.el-steps--horizontal) {
  .el-step__icon {
    width: 36px;
    height: 36px;
    font-size: 16px;
    font-weight: 600;
    background: #ffffff !important;
  }
  .el-step__head.is-process .el-step__icon {
    color: #ffffff !important;
    background: #1677ff !important;
    border-color: $zfb-blue !important;
  }
  .el-step__head.is-wait .el-step__icon {
    color: #c0c4cc !important;
    background: #ffffff !important;
    border: 2px solid #dcdfe6 !important;
  }
  .el-step__head.is-finish .el-step__icon {
    color: #ffffff !important;
    background: $zfb-blue !important;
    border-color: $zfb-blue !important;
  }
  .el-step__line {
    background-color: #e4e7ed !important;
  }
  .el-step__line-inner {
    border-width: 1px !important;
  }
  .el-step__title {
    font-size: 14px;
    line-height: 36px;
    color: #606266;
  }
  .el-step__head.is-process + .el-step__main .el-step__title {
    font-weight: 600;
    color: #303133;
  }
  .el-step__head.is-wait + .el-step__main .el-step__title {
    color: #c0c4cc;
  }
  .el-step__head.is-finish + .el-step__main .el-step__title {
    font-weight: 500;
    color: #606266;
  }
}
.page-layout {
  display: flex;
  gap: 32px;
  align-items: flex-start;
}
.main-column {
  flex: 1;
  min-width: 0;

  /* 滚到底时 max(scrollTop) 往往仍小于「经营信息」的锚点判定线，侧栏会一直停在前一节；底部留白增大可滚动距离 */
  padding-bottom: clamp(140px, 22vh, 400px);
}
.anchor-column {
  flex-shrink: 0;
  width: 160px;
}
.anchor-card {
  padding: 16px 12px;
}
:deep(.el-anchor__list) {
  border-left: 1px solid #ebeef5;
}
.anchor-title {
  margin-bottom: 12px;
  font-size: 13px;
  font-weight: 600;
  color: #303133;
}
.zfb-form {
  :deep(.el-form-item__label) {
    font-weight: 500;
    color: #606266;
  }
}
.form-block {
  padding-bottom: 8px;
  margin-bottom: 28px;
  scroll-margin-top: 72px;
  border-bottom: 1px solid #ebeef5;
  &:last-of-type {
    border-bottom: none;
  }
}
.section-head {
  display: flex;
  align-items: center;
  margin: 0 0 16px;
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}
.section-bar {
  display: inline-block;
  flex-shrink: 0;
  width: 4px;
  height: 16px;
  margin-right: 8px;
  background: $zfb-blue;
  border-radius: 2px;
}
.radio-stack {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}
.label-with-icon {
  display: inline-flex;
  gap: 4px;
  align-items: center;
}
.label-wrap-multiline {
  display: inline-block;
  max-width: 196px;
  line-height: 1.45;
  white-space: normal;
  vertical-align: middle;
}
.individual-merchant-alert {
  max-width: 410px;
  margin-bottom: 20px;
  margin-left: 200px;
}
.info-icon {
  color: #909399;
  cursor: help;
}
.license-upload-wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: flex-start;
}
.license-example {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.license-example-label {
  font-size: 12px;
  color: #909399;
}
.license-example-thumb {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 148px;
  height: 148px;
  overflow: hidden;
  background: #f5f7fa;
  border: 1px dashed #dcdfe6;
  border-radius: 6px;
}
.license-example-placeholder {
  font-size: 12px;
  color: #c0c4cc;
}
.id-example-thumb {
  position: relative;
}
.license-example-badge {
  position: absolute;
  top: 6px;
  right: 6px;
  padding: 2px 6px;
  font-size: 11px;
  color: #ffffff;
  background: rgb(0 0 0 / 45%);
  border-radius: 4px;
}
.id-upload-row {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
}
.id-upload-cell {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.id-upload-trigger {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: center;
  justify-content: center;
  line-height: 1.2;
}
.id-side-label {
  margin-top: 10px;
  font-size: 13px;
  color: #606266;
}
.id-upload-trigger .id-side-label {
  font-size: 12px;
  line-height: 1.3;
  text-align: center;
}
.upload-rules {
  margin-top: 12px;
  font-size: 12px;
  line-height: 1.65;
  color: #909399;
  p {
    margin: 0;
  }
}
.field-stack {
  width: 100%;
}
.field-tip {
  margin: 8px 0 0;
  font-size: 12px;
  line-height: 1.65;
  color: #909399;
}
.service-checks {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 20px;
}
.address-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  width: 100%;
  max-width: 720px;
}
.address-detail {
  flex: 1;
  min-width: 200px;
}
.footer-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
  justify-content: center;
  padding-top: 24px;
  margin-top: 8px;
  border-top: 1px solid #ebeef5;
}
.btn-primary-zfb {
  min-width: 120px;
  background: $zfb-blue;
  border-color: $zfb-blue;
  &:hover {
    background: #4096ff;
    border-color: #4096ff;
  }
}
:deep(.el-upload--picture-card) {
  --el-upload-picture-card-size: 148px;
}
:deep(.el-upload-list--picture-card .el-upload-list__item) {
  width: 148px;
  height: 148px;
}
:deep(.el-form-item__content) {
  display: block;
}
:deep(.anchor-card .el-anchor) {
  /* 实际滚动在 layout 的 el-main 上，不设 container 时监听 window，高亮不会随滚动更新 */
  --el-anchor-color: #606266;
  --el-anchor-active-color: #{$zfb-blue};
  --el-anchor-marker-bg-color: #{$zfb-blue};

  background: transparent;
}
:deep(.anchor-card .el-anchor__link) {
  padding: 6px 0;
  font-size: 13px;
}
:deep(.anchor-card .el-anchor__link.is-active) {
  font-weight: 600;
}
</style>
