/**
 * 表单提交 loading / 防重复点击 / 「未发起请求」超时守卫。
 * 为什么抽成公共模块：门店录入与医生录入提交流程一致，避免两页各自维护一套定时器与异常收尾逻辑。
 */

/** 点击后若超过该毫秒仍未真正发起请求，则取消 loading 并提示 */
export const SUBMIT_PREP_TIMEOUT_MS = 10000

/**
 * 清理「未发起请求」倒计时，避免页面销毁或重复 begin 时残留定时器。
 * @param {object} ctx 页面/组件实例（需挂 _submitPrepTimer）
 */
function clearPrepTimer(ctx) {
  if (ctx && ctx._submitPrepTimer) {
    clearTimeout(ctx._submitPrepTimer)
    ctx._submitPrepTimer = null
  }
}

/**
 * 开始提交：立刻 loading + 防重复 + 启动 10s「未发起请求」倒计时。
 * @param {object} ctx 需有 data.submitting
 * @param {{ title?: string }} [options]
 * @returns {boolean} false 表示已在提交中，调用方应直接 return
 */
export function beginSubmit(ctx, options = {}) {
  if (!ctx || ctx.submitting) return false
  ctx.submitting = true
  ctx._submitRequestStarted = false
  clearPrepTimer(ctx)
  uni.showLoading({ title: options.title || '提交中...', mask: true })
  // 10 秒内若仍未 markRequestStarted，说明卡在校验/组 payload，需收起 loading 并友好提示
  ctx._submitPrepTimer = setTimeout(() => {
    ctx._submitPrepTimer = null
    if (ctx._submitRequestStarted) return
    endSubmit(ctx, { toast: '提交超时，请稍后重试' })
  }, SUBMIT_PREP_TIMEOUT_MS)
  return true
}

/**
 * 标记已真正发起 API 请求：清除「未发起请求」倒计时，loading 继续等待接口返回。
 * @param {object} ctx
 */
export function markRequestStarted(ctx) {
  if (!ctx) return
  ctx._submitRequestStarted = true
  clearPrepTimer(ctx)
}

/**
 * 结束提交：清定时器、复位 submitting；默认关 loading，可选 toast。
 * 校验失败时 showError 已 showToast（会顶掉 loading），须传 skipHideLoading，否则 hideLoading 会把 toast 清掉。
 * @param {object} ctx
 * @param {{ toast?: string, skipHideLoading?: boolean }} [options]
 */
export function endSubmit(ctx, options = {}) {
  if (!ctx) return
  clearPrepTimer(ctx)
  ctx._submitRequestStarted = false
  ctx.submitting = false
  if (!options.skipHideLoading) {
    try {
      uni.hideLoading()
    } catch (e) {
      // hideLoading 在无 loading 时偶发抛错，忽略以免二次异常
    }
  }
  if (options.toast) {
    uni.showToast({ title: options.toast, icon: 'none' })
  }
}

/**
 * 统一跑完「校验 → 发请求 → 成功/失败/异常收尾」。
 * @param {object} ctx
 * @param {{
 *   validate: () => boolean,
 *   request: () => Promise<{ ok?: boolean, res?: any, msg?: string, data?: any }>,
 *   onSuccess: (w: any) => void,
 *   loadingTitle?: string,
 * }} options
 */
export function runSubmit(ctx, options) {
  const { validate, request, onSuccess, loadingTitle } = options || {}
  if (!beginSubmit(ctx, { title: loadingTitle })) return
  try {
    if (typeof validate === 'function' && !validate()) {
      // 校验失败：showError 已 toast（顶掉 loading），只复位状态，勿再 hideLoading
      endSubmit(ctx, { skipHideLoading: true })
      return
    }
    markRequestStarted(ctx)
    const reqPromise = typeof request === 'function' ? request() : null
    if (!reqPromise || typeof reqPromise.then !== 'function') {
      endSubmit(ctx, { toast: '提交异常，请稍后重试' })
      return
    }
    reqPromise
      .then((w) => {
        if (w && w.ok) {
          endSubmit(ctx)
          if (typeof onSuccess === 'function') onSuccess(w)
          return
        }
        const msg = (w && w.res && w.res.msg) || (w && w.msg) || '提交失败'
        endSubmit(ctx, { toast: msg })
      })
      .catch(() => {
        endSubmit(ctx, { toast: '提交异常，请稍后重试' })
      })
  } catch (e) {
    endSubmit(ctx, { toast: '提交异常，请稍后重试' })
  }
}
