import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
import {
  isFriendGiftAcceptanceMode,
  isWorkOrderGiftAvailable,
  WORK_ORDER_GIFT_PHASE,
} from '../../domain/work-order-acceptance-mode.js'
import {
  acceptWorkOrderAndSettle,
  acceptWorkOrderShareAndSettle,
  countWorkOrderPendingSharingSubmissions,
  createWorkOrderEvent,
  getWorkOrderShare,
  settleOverdueWorkOrder,
  submitWorkOrderShareAcceptance,
  updateWorkOrder,
  updateWorkOrderAcceptanceRecord,
  updateWorkOrderDraftAcceptance,
  updateWorkOrderShareAcceptanceRecord,
  updateWorkOrderShareDraftAcceptance,
  type WorkOrderRow,
  type WorkOrderShareRow,
} from '../../repositories/worker-platform/index.js'
import type { JsonObject } from '../../types/json.js'
import { createHttpError } from '../../utils/http.js'
import { addHours, nowIso } from '../../utils/time.js'
import { safeParseJson } from '../admin/admin-query-utils.js'
import {
  createWorkerAcceptanceAdminNotification,
  getWorkerAcceptanceReminder,
  remindWorkerAcceptanceAdminNotification,
} from '../admin/admin-notification-service.js'
import {
  publishWorkerWalletRealtimeChange,
  publishWorkOrderRealtimeChange,
} from '../realtime/realtime-event-service.js'
import {
  canWorkerAutoAcceptWholeOrder,
  mapWorkOrderForWorker,
  mapWorkOrderShare,
  normalizeStringArray,
  normalizeUploadedFiles,
  resolveWorkerPermissions,
} from './mappers.js'
import { getWorkerFinanceConfig } from './worker-finance-config-service.js'
import { publishWorkOrderParticipantChange } from './worker-order-realtime-service.js'
import {
  getRequiredWorkOrder,
  getRequiredWorker,
  requireActiveWorkerSession,
  type WorkerSession,
} from './worker-session-context-service.js'
import { normalizeWorkOrderTimeoutPolicy } from './work-order-timeout-policy.js'

const VIP_AUTO_ACCEPT_EVIDENCE_WINDOW_HOURS = 24

export async function submitWorkerOrderAcceptance(
  workOrderId: number | string,
  payload: JsonObject = {},
  session: WorkerSession,
) {
  requireActiveWorkerSession(session)
  const workOrder = await getRequiredWorkOrder(workOrderId)
  const workerId = Number(session.workerId)
  const worker = await getRequiredWorker(session.workerId)
  const sharingShare = await getWorkOrderShare(workOrder.id, workerId)
  if (sharingShare) {
    return submitWorkerSharingAcceptance(workOrder, sharingShare, payload, session)
  }
  const canAutoAcceptWithoutEvidence = isFriendGiftAcceptanceMode(workOrder.acceptance_mode)
    ? false
    : canWorkerAutoAcceptWholeOrder({
        worker,
        hasPersonalSharingShare: false,
      })
  const now = nowIso()
  // 好友赠送单在“待确认好友”阶段是等后台操作，等待期不计打手超时。
  const awaitingFriendConfirm =
    isFriendGiftAcceptanceMode(workOrder.acceptance_mode) &&
    workOrder.gift_phase === WORK_ORDER_GIFT_PHASE.MATERIAL_SUBMITTED
  if (
    workOrder.status === WORK_ORDER_STATUS.IN_PROGRESS &&
    !awaitingFriendConfirm &&
    workOrder.deadline_at &&
    new Date(workOrder.deadline_at).getTime() <= Date.now()
  ) {
    await settleOverdueWorkOrder({
      workOrderId: workOrder.id,
      policy: normalizeWorkOrderTimeoutPolicy(workOrder.timeout_policy),
      now,
    })
    throw createHttpError('任务已超时，系统已按超时策略处置', {
      statusCode: 409,
      errorCode: 'work_order_timeout_expired',
    })
  }
  if (Number(workOrder.assigned_worker_id || 0) !== workerId) {
    throw createHttpError('只能提交自己的订单', {
      statusCode: 403,
      errorCode: 'work_order_owner_required',
    })
  }
  if (
    ![WORK_ORDER_STATUS.IN_PROGRESS, WORK_ORDER_STATUS.PROBLEM].includes(workOrder.status as never)
  ) {
    throw createHttpError('当前状态不能提交验收', {
      statusCode: 409,
      errorCode: 'work_order_submit_status_invalid',
    })
  }
  // 好友赠送模式：必须等后台确认加好友且冷却结束后，才能提交赠送凭证。
  if (isFriendGiftAcceptanceMode(workOrder.acceptance_mode)) {
    if (
      workOrder.gift_phase !== WORK_ORDER_GIFT_PHASE.FRIEND_COUNTDOWN ||
      !isWorkOrderGiftAvailable(workOrder)
    ) {
      throw createHttpError('好友赠送冷却未结束，暂不能提交验收', {
        statusCode: 409,
        errorCode: 'work_order_gift_cooldown_active',
      })
    }
  }

  const { files, imageUrls, note } = resolveAcceptanceImages(
    payload,
    workOrder.draft_acceptance_json,
  )
  if (imageUrls.length === 0 && !canAutoAcceptWithoutEvidence) {
    throw createHttpError('请上传验收图片', {
      statusCode: 400,
      errorCode: 'work_order_acceptance_image_required',
    })
  }
  const acceptance = {
    note,
    files,
    imageUrls: [...new Set(imageUrls)],
    submittedAt: now,
    ...(canAutoAcceptWithoutEvidence
      ? {
          reviewMode: 'vip_auto',
          evidenceStatus: imageUrls.length > 0 ? 'complete' : 'pending',
          evidenceDueAt:
            imageUrls.length > 0 ? null : addHours(now, VIP_AUTO_ACCEPT_EVIDENCE_WINDOW_HOURS),
        }
      : {}),
  }
  const updated = await updateWorkOrder(workOrder.id, {
    status: WORK_ORDER_STATUS.PENDING_ACCEPTANCE,
    acceptance_json: acceptance,
    draft_acceptance_json: {},
    submitted_at: now,
    updated_at: now,
  })
  await createWorkOrderEvent({
    workOrderId: workOrder.id,
    actorType: 'worker',
    actorId: String(session.workerId),
    eventType: 'acceptance_submitted',
    fromStatus: workOrder.status,
    toStatus: WORK_ORDER_STATUS.PENDING_ACCEPTANCE,
    payloadJson: JSON.stringify({
      imageCount: imageUrls.length,
      autoAccepted: canAutoAcceptWithoutEvidence,
      evidenceDueAt: acceptance.evidenceDueAt || null,
    }),
    now,
  })
  // 好友赠送模式必须由后台人工验收赠送凭证，内部打手与 VIP 免审核直通均不适用。
  if (
    !isFriendGiftAcceptanceMode(workOrder.acceptance_mode) &&
    (worker.worker_type === 'internal' || canAutoAcceptWithoutEvidence)
  ) {
    const { order: acceptedOrder, failureReason } = await acceptWorkOrderAndSettle({
      workOrderId: workOrder.id,
      unfreezeDays: getWorkerFinanceConfig().depositUnfreezeDays,
      rewardUnfreezeEnabled: getWorkerFinanceConfig().rewardUnfreezeEnabled,
      now,
      actorType: 'worker',
      actorName: worker.display_name || worker.username || '',
    })
    if (failureReason === 'sharing_pending_submissions') {
      throw createHttpError('还有拼单打手未提交验收资料，暂不能统一验收', {
        statusCode: 409,
        errorCode: 'work_order_sharing_pending_submissions',
      })
    }
    if (!acceptedOrder) {
      throw createHttpError('免审核验收失败，请稍后重试', {
        statusCode: 409,
        errorCode: 'work_order_internal_auto_accept_failed',
      })
    }
    await createWorkOrderEvent({
      workOrderId: workOrder.id,
      actorType: 'worker',
      actorId: String(session.workerId),
      eventType: worker.worker_type === 'internal' ? 'accepted_by_internal' : 'accepted_by_vip',
      fromStatus: WORK_ORDER_STATUS.PENDING_ACCEPTANCE,
      toStatus: WORK_ORDER_STATUS.ACCEPTED,
      payloadJson: JSON.stringify({
        autoAccepted: true,
        evidenceStatus: acceptance.evidenceStatus || 'complete',
        evidenceDueAt: acceptance.evidenceDueAt || null,
      }),
      now,
    })
    publishWorkOrderRealtimeChange({
      workOrderId: Number(workOrder.id),
      workerIds: [Number(worker.id)],
    })
    publishWorkerWalletRealtimeChange(Number(worker.id))
    return {
      order: mapWorkOrderForWorker(acceptedOrder, resolveWorkerPermissions(worker)),
    }
  }
  await createWorkerAcceptanceAdminNotification({
    workOrderId: Number(workOrder.id),
    workOrderNo: workOrder.work_order_no,
    productName: workOrder.product_name,
    workerName: worker.display_name || worker.username,
    imageCount: imageUrls.length,
  })
  publishWorkOrderRealtimeChange({
    workOrderId: Number(workOrder.id),
    workerIds: [Number(worker.id)],
  })
  return {
    order: mapWorkOrderForWorker(updated || workOrder, resolveWorkerPermissions(worker)),
  }
}

/** 打手在提交验收后催促后台处理；频率和次数均由服务端控制。 */
export async function remindWorkerOrderAcceptance(
  workOrderId: number | string,
  session: WorkerSession,
) {
  requireActiveWorkerSession(session)
  const workOrder = await getRequiredWorkOrder(workOrderId)
  if (
    workOrder.sharing_enabled ||
    Number(workOrder.assigned_worker_id || 0) !== Number(session.workerId)
  ) {
    throw createHttpError('只能催促自己提交的整单验收', {
      statusCode: 403,
      errorCode: 'work_order_acceptance_reminder_owner_required',
    })
  }
  if (workOrder.status !== WORK_ORDER_STATUS.PENDING_ACCEPTANCE) {
    throw createHttpError('当前订单无需催验收', {
      statusCode: 409,
      errorCode: 'work_order_acceptance_reminder_status_invalid',
    })
  }
  const submittedAt = Date.parse(String(workOrder.submitted_at || ''))
  const now = Date.now()
  const firstReminderAt = submittedAt + 10 * 60 * 1000
  if (!Number.isFinite(submittedAt) || now < firstReminderAt) {
    throw createHttpError('提交验收满 10 分钟后才可催验收', {
      statusCode: 409,
      errorCode: 'work_order_acceptance_reminder_too_early',
    })
  }

  let notification = await getWorkerAcceptanceReminder(Number(workOrder.id))
  if (!notification) {
    const worker = await getRequiredWorker(session.workerId)
    await createWorkerAcceptanceAdminNotification({
      workOrderId: Number(workOrder.id),
      workOrderNo: workOrder.work_order_no,
      productName: workOrder.product_name,
      workerName: worker.display_name || worker.username,
      imageCount: normalizeStringArray(safeParseJson(workOrder.acceptance_json).imageUrls).length,
    })
    notification = await getWorkerAcceptanceReminder(Number(workOrder.id))
  }
  if (!notification) {
    throw createHttpError('催验收待办创建失败，请稍后重试', {
      statusCode: 409,
      errorCode: 'work_order_acceptance_reminder_notification_missing',
    })
  }
  if (Number(notification.reminder_count || 0) >= 3) {
    throw createHttpError('该订单最多催验收 3 次', {
      statusCode: 409,
      errorCode: 'work_order_acceptance_reminder_limit_reached',
    })
  }
  const lastRemindedAt = Date.parse(String(notification.last_reminded_at || ''))
  const nextRemindAt = lastRemindedAt + 30 * 60 * 1000
  if (Number.isFinite(lastRemindedAt) && now < nextRemindAt) {
    throw createHttpError('每 30 分钟可催验收一次，请稍后再试', {
      statusCode: 409,
      errorCode: 'work_order_acceptance_reminder_cooldown',
    })
  }

  const reminded = await remindWorkerAcceptanceAdminNotification(Number(workOrder.id))
  if (!reminded) {
    throw createHttpError('订单状态已变化，请刷新后重试', {
      statusCode: 409,
      errorCode: 'work_order_acceptance_reminder_conflict',
    })
  }
  const remindedAt = new Date(reminded.last_reminded_at || new Date().toISOString()).getTime()
  await createWorkOrderEvent({
    workOrderId: Number(workOrder.id),
    actorType: 'worker',
    actorId: String(session.workerId),
    eventType: 'acceptance_reminded',
    fromStatus: WORK_ORDER_STATUS.PENDING_ACCEPTANCE,
    toStatus: WORK_ORDER_STATUS.PENDING_ACCEPTANCE,
    payloadJson: JSON.stringify({ reminderCount: reminded.reminder_count }),
    now: new Date(reminded.last_reminded_at || new Date().toISOString()).toISOString(),
  })
  return {
    reminderCount: Number(reminded.reminder_count || 0),
    nextRemindAt: new Date(remindedAt + 30 * 60 * 1000).toISOString(),
  }
}

/** 已验收订单可追加验收图片，不改变订单状态和结算结果。 */
export async function supplementWorkerAcceptedOrderEvidence(
  workOrderId: number | string,
  payload: JsonObject = {},
  session: WorkerSession,
) {
  requireActiveWorkerSession(session)
  const workOrder = await getRequiredWorkOrder(workOrderId)
  const worker = await getRequiredWorker(session.workerId)
  const sharingShare = await getWorkOrderShare(workOrder.id, session.workerId)
  if (sharingShare) {
    return supplementWorkerAcceptedSharingEvidence(workOrder, sharingShare, payload, session)
  }
  if (Number(workOrder.assigned_worker_id || 0) !== Number(session.workerId)) {
    throw createHttpError('只能补充自己的订单验收图片', {
      statusCode: 403,
      errorCode: 'work_order_owner_required',
    })
  }
  if (workOrder.status !== WORK_ORDER_STATUS.ACCEPTED) {
    throw createHttpError('只有已验收订单可以补充验收图片', {
      statusCode: 409,
      errorCode: 'work_order_evidence_supplement_status_invalid',
    })
  }

  const now = nowIso()
  const previous = safeParseJson(workOrder.acceptance_json)
  const mergedEvidence = mergeAcceptanceEvidence(previous, payload.files)
  if (!mergedEvidence.changed) {
    throw createHttpError('请上传新的验收图片', {
      statusCode: 400,
      errorCode: 'work_order_evidence_supplement_image_required',
    })
  }
  const acceptance = {
    ...previous,
    files: mergedEvidence.files,
    imageUrls: mergedEvidence.imageUrls,
    evidenceStatus: 'complete',
    evidenceSupplementedAt: now,
    updatedAt: now,
  }
  const updated = await updateWorkOrderAcceptanceRecord({
    workOrderId: workOrder.id,
    acceptanceJson: JSON.stringify(acceptance),
    now,
  })
  await createWorkOrderEvent({
    workOrderId: workOrder.id,
    actorType: 'worker',
    actorId: String(session.workerId),
    eventType: 'acceptance_evidence_supplemented',
    fromStatus: WORK_ORDER_STATUS.ACCEPTED,
    toStatus: WORK_ORDER_STATUS.ACCEPTED,
    payloadJson: JSON.stringify({
      addedImageCount: mergedEvidence.addedFileCount,
      totalImageCount: mergedEvidence.imageUrls.length,
    }),
    now,
  })
  publishWorkOrderRealtimeChange({ workOrderId: Number(workOrder.id) })
  return {
    order: mapWorkOrderForWorker(updated || workOrder, resolveWorkerPermissions(worker)),
  }
}

async function submitWorkerSharingAcceptance(
  workOrder: WorkOrderRow,
  sharingShare: WorkOrderShareRow,
  payload: JsonObject = {},
  session: WorkerSession,
) {
  if (workOrder.status === WORK_ORDER_STATUS.ACCEPTED) {
    throw createHttpError('该拼单已验收完成', {
      statusCode: 409,
      errorCode: 'work_order_sharing_accepted',
    })
  }
  const now = nowIso()
  const worker = await getRequiredWorker(session.workerId)
  const canAutoAcceptWithoutEvidence = resolveWorkerPermissions(worker).autoAcceptWithoutEvidence
  const { files, imageUrls, note } = resolveAcceptanceImages(
    payload,
    sharingShare.draft_acceptance_json,
  )
  if (imageUrls.length === 0 && !canAutoAcceptWithoutEvidence) {
    throw createHttpError('请上传验收图片', {
      statusCode: 400,
      errorCode: 'work_order_acceptance_image_required',
    })
  }
  const acceptance = {
    note,
    files,
    imageUrls: [...new Set(imageUrls)],
    submittedAt: now,
    ...(canAutoAcceptWithoutEvidence
      ? {
          reviewMode: 'vip_auto',
          evidenceStatus: imageUrls.length > 0 ? 'complete' : 'pending',
          evidenceDueAt:
            imageUrls.length > 0 ? null : addHours(now, VIP_AUTO_ACCEPT_EVIDENCE_WINDOW_HOURS),
        }
      : {}),
  }
  const result = await submitWorkOrderShareAcceptance({
    workOrderId: Number(workOrder.id),
    workerId: Number(session.workerId),
    acceptanceJson: JSON.stringify(acceptance),
    now,
  })
  if (result.failureReason === 'share_status_invalid') {
    throw createHttpError('当前拼单份额已提交，请勿重复提交', {
      statusCode: 409,
      errorCode: 'work_order_sharing_share_submitted',
    })
  }
  if (result.failureReason === 'work_order_status_invalid') {
    throw createHttpError('当前拼单状态不能提交验收资料，请联系管理员', {
      statusCode: 409,
      errorCode: 'work_order_sharing_submit_status_invalid',
    })
  }
  if (!result.share) {
    throw createHttpError('未找到拼单份额', {
      statusCode: 404,
      errorCode: 'work_order_sharing_share_not_found',
    })
  }
  if (canAutoAcceptWithoutEvidence) {
    const accepted = await acceptWorkOrderShareAndSettle({
      workOrderId: Number(workOrder.id),
      shareId: Number(result.share.id),
      unfreezeDays: getWorkerFinanceConfig().depositUnfreezeDays,
      rewardUnfreezeEnabled: getWorkerFinanceConfig().rewardUnfreezeEnabled,
      now,
      actorType: 'worker',
      actorName: worker.display_name || worker.username || '',
    })
    if (!accepted.share || !accepted.order) {
      throw createHttpError('VIP 免审核验收失败，请稍后重试', {
        statusCode: 409,
        errorCode: 'work_order_sharing_vip_auto_accept_failed',
      })
    }
    await publishWorkOrderParticipantChange(Number(workOrder.id), {
      workerIds: [Number(session.workerId)],
      walletChangedWorkerIds: [Number(session.workerId)],
    })
    return {
      share: mapWorkOrderShare(accepted.share),
      sharingPendingCount: await countWorkOrderPendingSharingSubmissions(Number(workOrder.id)),
    }
  }
  await publishWorkOrderParticipantChange(Number(workOrder.id), {
    workerIds: [Number(session.workerId)],
  })
  return {
    share: mapWorkOrderShare(result.share),
    sharingPendingCount: await countWorkOrderPendingSharingSubmissions(Number(workOrder.id)),
  }
}

/** 已验收拼单份额可追加验收图片，不改变订单状态和结算结果。 */
async function supplementWorkerAcceptedSharingEvidence(
  workOrder: WorkOrderRow,
  sharingShare: WorkOrderShareRow,
  payload: JsonObject,
  session: WorkerSession,
) {
  if (sharingShare.status !== 'accepted') {
    throw createHttpError('只有已验收的拼单份额可以补充验收图片', {
      statusCode: 409,
      errorCode: 'work_order_sharing_evidence_supplement_status_invalid',
    })
  }

  const now = nowIso()
  const previous = safeParseJson(sharingShare.acceptance_json)
  const mergedEvidence = mergeAcceptanceEvidence(previous, payload.files)
  if (!mergedEvidence.changed) {
    throw createHttpError('请上传新的验收图片', {
      statusCode: 400,
      errorCode: 'work_order_sharing_evidence_supplement_image_required',
    })
  }
  const acceptance = {
    ...previous,
    files: mergedEvidence.files,
    imageUrls: mergedEvidence.imageUrls,
    evidenceStatus: 'complete',
    evidenceSupplementedAt: now,
    updatedAt: now,
  }
  const updated = await updateWorkOrderShareAcceptanceRecord({
    workOrderId: Number(workOrder.id),
    workerId: Number(session.workerId),
    acceptanceJson: JSON.stringify(acceptance),
    now,
  })
  await createWorkOrderEvent({
    workOrderId: workOrder.id,
    actorType: 'worker',
    actorId: String(session.workerId),
    eventType: 'sharing_acceptance_evidence_supplemented',
    fromStatus: WORK_ORDER_STATUS.ACCEPTED,
    toStatus: WORK_ORDER_STATUS.ACCEPTED,
    payloadJson: JSON.stringify({
      workerId: Number(session.workerId),
      addedImageCount: mergedEvidence.addedFileCount,
      totalImageCount: mergedEvidence.imageUrls.length,
    }),
    now,
  })
  await publishWorkOrderParticipantChange(Number(workOrder.id), {
    workerIds: [Number(session.workerId)],
  })
  return { share: mapWorkOrderShare(updated || sharingShare) }
}

/** 从提交或草稿载荷中解析验收图片与说明。 */
function resolveAcceptanceImages(payload: JsonObject, draftValue: unknown) {
  const files = normalizeUploadedFiles(payload.files)
  const imageUrls = [
    ...files.map((file) => file.url || file.mediumUrl || file.thumbnailUrl).filter(Boolean),
    ...normalizeStringArray(payload.imageUrls),
  ]
  if (imageUrls.length > 0) {
    return {
      files,
      imageUrls: [...new Set(imageUrls)],
      note: String(payload.note ?? '').trim(),
    }
  }
  const draft = safeParseJson(draftValue)
  return {
    files: normalizeUploadedFiles(draft.files),
    imageUrls: [...new Set(normalizeStringArray(draft.imageUrls))],
    note: String(payload.note ?? draft.note ?? '').trim(),
  }
}

/** 暂存验收图片或说明；已提交验收时更新已提交资料。 */
export async function saveWorkerOrderAcceptanceDraft(
  workOrderId: number | string,
  payload: JsonObject = {},
  session: WorkerSession,
) {
  requireActiveWorkerSession(session)
  const workOrder = await getRequiredWorkOrder(workOrderId)
  const workerId = Number(session.workerId)
  const sharingShare = await getWorkOrderShare(workOrder.id, workerId)
  if (sharingShare) {
    return saveWorkerSharingAcceptanceDraft(workOrder, sharingShare, payload, session)
  }
  if (Number(workOrder.assigned_worker_id || 0) !== workerId) {
    throw createHttpError('只能操作自己的订单', {
      statusCode: 403,
      errorCode: 'work_order_owner_required',
    })
  }
  const now = nowIso()
  const { files, imageUrls } = resolveAcceptanceImages(payload, {})
  const worker = await getRequiredWorker(session.workerId)

  if (workOrder.status === WORK_ORDER_STATUS.PENDING_ACCEPTANCE) {
    if (imageUrls.length === 0) {
      throw createHttpError('请至少保留一张验收图片', {
        statusCode: 400,
        errorCode: 'work_order_acceptance_image_required',
      })
    }
    const previous = safeParseJson(workOrder.acceptance_json)
    const acceptance = {
      note: String(payload.note ?? previous.note ?? '').trim(),
      files,
      imageUrls: [...new Set(imageUrls)],
      submittedAt: previous.submittedAt || workOrder.submitted_at || now,
      updatedAt: now,
    }
    const updated = await updateWorkOrderAcceptanceRecord({
      workOrderId: workOrder.id,
      acceptanceJson: JSON.stringify(acceptance),
      now,
    })
    await createWorkOrderEvent({
      workOrderId: workOrder.id,
      actorType: 'worker',
      actorId: String(session.workerId),
      eventType: 'acceptance_updated',
      fromStatus: workOrder.status,
      toStatus: workOrder.status,
      payloadJson: JSON.stringify({ imageCount: imageUrls.length }),
      now,
    })
    await publishWorkOrderParticipantChange(Number(workOrder.id), {
      workerIds: [Number(session.workerId)],
    })
    return {
      order: mapWorkOrderForWorker(updated || workOrder, resolveWorkerPermissions(worker)),
    }
  }

  if (
    ![WORK_ORDER_STATUS.IN_PROGRESS, WORK_ORDER_STATUS.PROBLEM].includes(workOrder.status as never)
  ) {
    throw createHttpError('当前状态不能保存验收图片', {
      statusCode: 409,
      errorCode: 'work_order_draft_status_invalid',
    })
  }
  const draft = {
    note: String(payload.note || '').trim(),
    files,
    imageUrls: [...new Set(imageUrls)],
    updatedAt: now,
  }
  const updated = await updateWorkOrderDraftAcceptance({
    workOrderId: workOrder.id,
    draftJson: JSON.stringify(draft),
    now,
  })
  await createWorkOrderEvent({
    workOrderId: workOrder.id,
    actorType: 'worker',
    actorId: String(session.workerId),
    eventType: 'acceptance_draft_saved',
    fromStatus: workOrder.status,
    toStatus: workOrder.status,
    payloadJson: JSON.stringify({ imageCount: imageUrls.length }),
    now,
  })
  await publishWorkOrderParticipantChange(Number(workOrder.id), {
    workerIds: [Number(session.workerId)],
  })
  return {
    order: mapWorkOrderForWorker(updated || workOrder, resolveWorkerPermissions(worker)),
  }
}

async function saveWorkerSharingAcceptanceDraft(
  workOrder: WorkOrderRow,
  sharingShare: WorkOrderShareRow,
  payload: JsonObject = {},
  session: WorkerSession,
) {
  if (workOrder.status === WORK_ORDER_STATUS.ACCEPTED) {
    throw createHttpError('该拼单已验收完成，不能再修改验收图片', {
      statusCode: 409,
      errorCode: 'work_order_sharing_accepted',
    })
  }
  const now = nowIso()
  const { files, imageUrls } = resolveAcceptanceImages(payload, {})

  if (sharingShare.status === 'submitted') {
    if (imageUrls.length === 0) {
      throw createHttpError('请至少保留一张验收图片', {
        statusCode: 400,
        errorCode: 'work_order_acceptance_image_required',
      })
    }
    const previous = safeParseJson(sharingShare.acceptance_json)
    const acceptance = {
      note: String(payload.note ?? previous.note ?? '').trim(),
      files,
      imageUrls: [...new Set(imageUrls)],
      submittedAt: previous.submittedAt || sharingShare.submitted_at || now,
      updatedAt: now,
    }
    const share = await updateWorkOrderShareAcceptanceRecord({
      workOrderId: Number(workOrder.id),
      workerId: Number(session.workerId),
      acceptanceJson: JSON.stringify(acceptance),
      now,
    })
    await createWorkOrderEvent({
      workOrderId: workOrder.id,
      actorType: 'worker',
      actorId: String(session.workerId),
      eventType: 'sharing_acceptance_updated',
      fromStatus: workOrder.status,
      toStatus: workOrder.status,
      payloadJson: JSON.stringify({
        workerId: Number(session.workerId),
        imageCount: imageUrls.length,
      }),
      now,
    })
    await publishWorkOrderParticipantChange(Number(workOrder.id), {
      workerIds: [Number(session.workerId)],
    })
    return { share: share ? mapWorkOrderShare(share) : mapWorkOrderShare(sharingShare) }
  }

  if (sharingShare.status !== 'joined') {
    throw createHttpError('当前拼单状态不能保存验收图片', {
      statusCode: 409,
      errorCode: 'work_order_sharing_draft_status_invalid',
    })
  }
  const draft = {
    note: String(payload.note || '').trim(),
    files,
    imageUrls: [...new Set(imageUrls)],
    updatedAt: now,
  }
  const share = await updateWorkOrderShareDraftAcceptance({
    workOrderId: Number(workOrder.id),
    workerId: Number(session.workerId),
    draftJson: JSON.stringify(draft),
    now,
  })
  await createWorkOrderEvent({
    workOrderId: workOrder.id,
    actorType: 'worker',
    actorId: String(session.workerId),
    eventType: 'sharing_acceptance_draft_saved',
    fromStatus: workOrder.status,
    toStatus: workOrder.status,
    payloadJson: JSON.stringify({
      workerId: Number(session.workerId),
      imageCount: imageUrls.length,
    }),
    now,
  })
  await publishWorkOrderParticipantChange(Number(workOrder.id), {
    workerIds: [Number(session.workerId)],
  })
  return { share: share ? mapWorkOrderShare(share) : mapWorkOrderShare(sharingShare) }
}

function mergeAcceptanceEvidence(previous: Record<string, unknown>, uploadedValue: unknown) {
  const existingFiles = normalizeUploadedFiles(previous.files)
  const uploadedFiles = normalizeUploadedFiles(uploadedValue)
  const files = [...existingFiles]
  const fileIdentities = new Set(
    existingFiles.map((file) => file.objectKey || file.url || file.mediumUrl || file.thumbnailUrl),
  )
  for (const file of uploadedFiles) {
    const identity = file.objectKey || file.url || file.mediumUrl || file.thumbnailUrl
    if (!identity || fileIdentities.has(identity)) continue
    fileIdentities.add(identity)
    files.push(file)
  }
  const previousImageUrls = normalizeStringArray(previous.imageUrls)
  const imageUrls = [
    ...new Set([
      ...previousImageUrls,
      ...files.map((file) => file.url || file.mediumUrl || file.thumbnailUrl).filter(Boolean),
    ]),
  ]
  return {
    files,
    imageUrls,
    addedFileCount: files.length - existingFiles.length,
    changed: files.length !== existingFiles.length || imageUrls.length !== previousImageUrls.length,
  }
}
