import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
import {
  isFriendGiftAcceptanceMode,
  isWorkOrderGiftAvailable,
  normalizeWorkOrderAcceptanceMode,
  normalizeWorkOrderGiftCooldownHours,
  normalizeWorkOrderGiftCooldownMinutes,
  resolveWorkOrderGiftPhase,
  WORK_ORDER_ACCEPTANCE_MODE,
  WORK_ORDER_GIFT_PHASE,
} from '../../domain/work-order-acceptance-mode.js'
import {
  type WorkCategoryRow,
  type WorkOrderCapabilities,
  type WorkOrderRow,
  type WorkOrderShareRow,
} from '../../repositories/worker-platform/index.js'
import type { JsonObject } from '../../types/json.js'
import { safeParseJson } from '../admin/admin-query-utils.js'
import { refreshUploadedFileUrls } from '../file-storage/file-storage-service.js'
import { DEFAULT_DEPOSIT_THRESHOLD_AMOUNT } from './worker-finance-mappers.js'
import { normalizeUploadedFiles } from './worker-input-normalizers.js'
import { resolveFreezeDepositAmount } from './worker-permission-utils.js'
import {
  mapAcceptanceForResponse,
  resolveCollectSubmittedFieldValues,
} from './work-order-material-mappers.js'
import { resolveRequirementFields } from './work-order-requirement-fields.js'

export function mapWorkCategory(category: WorkCategoryRow | null | undefined) {
  if (!category) return null
  return {
    categoryId: Number(category.id),
    categoryKey: category.category_key,
    name: category.name,
    sortOrder: Number(category.sort_order || 100),
    status: category.status,
    createdAt: category.created_at,
    updatedAt: category.updated_at,
  }
}

/** 读取工单资料：刷新买家主页截图等文件的访问链接（签名 15 分钟过期，读取时必须重签） */
export function mapWorkOrderMaterial(value: unknown) {
  const material = safeParseJson(value)
  const collect =
    material.collect && typeof material.collect === 'object' && !Array.isArray(material.collect)
      ? (material.collect as JsonObject)
      : null
  if (!collect) {
    return material
  }
  return {
    ...material,
    collect: {
      ...collect,
      screenshots: normalizeUploadedFiles(collect.screenshots).map(refreshUploadedFileUrls),
    },
  }
}

/** 读取好友赠送模式的打手本人资料；主页截图访问链接需要读取时重签。 */
export function mapWorkOrderBoosterMaterial(value: unknown) {
  const material = safeParseJson(value)
  return {
    fields:
      material.fields && typeof material.fields === 'object' && !Array.isArray(material.fields)
        ? (material.fields as Record<string, string>)
        : {},
    screenshots: normalizeUploadedFiles(material.screenshots).map(refreshUploadedFileUrls),
    note: String(material.note || ''),
    submittedAt: String(material.submittedAt || ''),
  }
}

/** 统一计算后台使用的工单业务状态，避免拼单订单继续直接暴露母工单 open。 */
export function resolveWorkOrderOperationalStatus(workOrder: WorkOrderRow): string {
  const activeShareQuantity = Math.max(0, Number(workOrder.active_share_quantity || 0))
  const pendingShareCount = Math.max(0, Number(workOrder.pending_share_count || 0))
  const sharingTotalQuantity = Math.max(1, Number(workOrder.sharing_total_quantity || 1))
  const hasActiveShares = activeShareQuantity > 0
  const sharingFilled =
    workOrder.sharing_enabled === true && activeShareQuantity >= sharingTotalQuantity

  if (workOrder.status === WORK_ORDER_STATUS.OPEN && workOrder.sharing_enabled && hasActiveShares) {
    return sharingFilled && pendingShareCount === 0
      ? WORK_ORDER_STATUS.PENDING_ACCEPTANCE
      : WORK_ORDER_STATUS.IN_PROGRESS
  }
  return workOrder.status
}

/** 汇总拼单参与者，已撤销份额不应继续展示为当前打手。 */
export function mapWorkOrderSharingWorkers(shares: WorkOrderShareRow[]) {
  const workers = new Map<
    number,
    { workerId: number; username: string; displayName: string; quantity: number }
  >()
  for (const share of shares) {
    if (share.status === 'cancelled') continue
    const workerId = Number(share.worker_id || 0)
    if (workerId <= 0) continue
    const existing = workers.get(workerId)
    if (existing) {
      existing.quantity += Number(share.quantity || 0)
      continue
    }
    const username = String(share.worker_username || '').trim()
    workers.set(workerId, {
      workerId,
      username,
      displayName: String(share.worker_display_name || username || `打手#${workerId}`).trim(),
      quantity: Number(share.quantity || 0),
    })
  }
  return [...workers.values()]
}

/** 取消来源：由触发取消的事件类型推导，用于列表与详情展示。 */
function resolveWorkOrderCancelSource(cancelEventType: string | null | undefined) {
  const eventType = String(cancelEventType || '').trim()
  if (eventType === 'cancelled_by_admin') return '后台撤单'
  if (eventType.startsWith('problem_')) return '问题单处置'
  if (eventType.startsWith('timeout_')) return '超时自动取消'
  return eventType || '未知来源'
}

export function mapWorkOrderAdmin(workOrder: WorkOrderRow, shares?: WorkOrderShareRow[]) {
  const activeShareQuantity = Math.max(0, Number(workOrder.active_share_quantity || 0))
  const pendingShareCount = Math.max(0, Number(workOrder.pending_share_count || 0))
  const sharingTotalQuantity = Math.max(1, Number(workOrder.sharing_total_quantity || 1))
  const hasActiveShares = activeShareQuantity > 0
  const sharingFilled =
    workOrder.sharing_enabled === true && activeShareQuantity >= sharingTotalQuantity
  const status = resolveWorkOrderOperationalStatus(workOrder)
  const acceptanceMode = normalizeWorkOrderAcceptanceMode(workOrder.acceptance_mode)
  const isFriendGift = acceptanceMode === WORK_ORDER_ACCEPTANCE_MODE.FRIEND_GIFT
  const giftPhase = String(workOrder.gift_phase || '').trim()
  const hallAvailable =
    workOrder.status === WORK_ORDER_STATUS.OPEN &&
    (!workOrder.sharing_enabled || activeShareQuantity < sharingTotalQuantity)
  const editableBeforeClaim =
    !workOrder.assigned_worker_id &&
    (workOrder.status === WORK_ORDER_STATUS.PENDING_MATERIAL ||
      workOrder.status === WORK_ORDER_STATUS.UNASSIGNED ||
      (workOrder.status === WORK_ORDER_STATUS.OPEN && !hasActiveShares))
  const capabilities: WorkOrderCapabilities = {
    canEdit: editableBeforeClaim,
    canConfigureSharing: editableBeforeClaim,
    canAssign:
      !workOrder.assigned_worker_id &&
      (workOrder.status === WORK_ORDER_STATUS.UNASSIGNED ||
        (workOrder.status === WORK_ORDER_STATUS.OPEN && !hasActiveShares)),
    canPin: hallAvailable || Boolean(workOrder.pinned_at),
    canUnpublish:
      workOrder.status === WORK_ORDER_STATUS.OPEN &&
      !hasActiveShares &&
      !workOrder.assigned_worker_id,
    canUpdateMaterial:
      workOrder.status === WORK_ORDER_STATUS.PENDING_MATERIAL ||
      workOrder.status === WORK_ORDER_STATUS.UNASSIGNED ||
      workOrder.status === WORK_ORDER_STATUS.OPEN ||
      workOrder.status === WORK_ORDER_STATUS.IN_PROGRESS,
    canAccept: status === WORK_ORDER_STATUS.PENDING_ACCEPTANCE,
    canMarkProblem:
      status === WORK_ORDER_STATUS.IN_PROGRESS || status === WORK_ORDER_STATUS.PENDING_ACCEPTANCE,
    canDelete:
      !workOrder.assigned_worker_id &&
      !hasActiveShares &&
      [
        WORK_ORDER_STATUS.PENDING_MATERIAL,
        WORK_ORDER_STATUS.UNASSIGNED,
        WORK_ORDER_STATUS.CANCELLED,
      ].includes(workOrder.status as never),
    canReopen: workOrder.status === WORK_ORDER_STATUS.CANCELLED && !hasActiveShares,
    canPublish:
      workOrder.status === WORK_ORDER_STATUS.UNASSIGNED && Number(workOrder.reward_amount || 0) > 0,
    canCancel: status === WORK_ORDER_STATUS.IN_PROGRESS && Boolean(workOrder.assigned_worker_id),
    canCancelSharing:
      workOrder.sharing_enabled === true &&
      hasActiveShares &&
      ['open', 'pending_acceptance', 'in_progress'].includes(workOrder.status),
    canResolveProblem: workOrder.status === WORK_ORDER_STATUS.PROBLEM,
    canDeduct: workOrder.status === WORK_ORDER_STATUS.ACCEPTED,
    canConfirmFriend:
      isFriendGift &&
      workOrder.status === WORK_ORDER_STATUS.IN_PROGRESS &&
      giftPhase === WORK_ORDER_GIFT_PHASE.MATERIAL_SUBMITTED,
    canCompleteGiftCooldown:
      isFriendGift &&
      [WORK_ORDER_STATUS.IN_PROGRESS, WORK_ORDER_STATUS.PROBLEM].includes(
        workOrder.status as never,
      ) &&
      giftPhase === WORK_ORDER_GIFT_PHASE.FRIEND_COUNTDOWN &&
      !isWorkOrderGiftAvailable(workOrder),
    canResetGiftFlow:
      isFriendGift &&
      [WORK_ORDER_STATUS.IN_PROGRESS, WORK_ORDER_STATUS.PROBLEM].includes(
        workOrder.status as never,
      ) &&
      [WORK_ORDER_GIFT_PHASE.MATERIAL_SUBMITTED, WORK_ORDER_GIFT_PHASE.FRIEND_COUNTDOWN].includes(
        giftPhase as never,
      ),
  }
  return {
    workOrderId: Number(workOrder.id),
    orderId: workOrder.order_id ? Number(workOrder.order_id) : null,
    orderItemId: workOrder.order_item_id ? Number(workOrder.order_item_id) : null,
    workOrderNo: workOrder.work_order_no,
    platformOrderId: workOrder.platform_order_id,
    productName: workOrder.product_name,
    categoryId: workOrder.category_id ? Number(workOrder.category_id) : null,
    categoryName: workOrder.category_name || '',
    status,
    rawStatus: workOrder.status,
    hallAvailable,
    acceptanceMode,
    ...(isFriendGift
      ? {
          gift: {
            phase: resolveWorkOrderGiftPhase(workOrder),
            rawPhase: giftPhase,
            cooldownHours: normalizeWorkOrderGiftCooldownHours(workOrder.gift_cooldown_hours),
            cooldownMinutes: normalizeWorkOrderGiftCooldownMinutes(workOrder.gift_cooldown_minutes),
            friendAddedAt: workOrder.friend_added_at,
            giftAvailableAt: workOrder.gift_available_at,
            boosterMaterial: mapWorkOrderBoosterMaterial(workOrder.booster_material_json),
          },
        }
      : {}),
    sharingProgress: {
      joinedQuantity: activeShareQuantity,
      pendingSubmissionCount: pendingShareCount,
      remainingQuantity: Math.max(0, sharingTotalQuantity - activeShareQuantity),
      filled: sharingFilled,
    },
    capabilities,
    rewardAmount: Number(workOrder.reward_amount || 0),
    requiredDepositAmount: Number(workOrder.required_deposit_amount || 0),
    sharing: {
      enabled: workOrder.sharing_enabled === true,
      totalQuantity: Number(workOrder.sharing_total_quantity || 1),
      unitReward: Number(workOrder.sharing_unit_reward || 0),
    },
    timeoutMinutes: Number(workOrder.timeout_minutes || 0),
    timeoutPolicy: String(workOrder.timeout_policy || 'reopen').trim(),
    deadlineAt: workOrder.deadline_at,
    depositThresholdAmount: Number(
      workOrder.deposit_threshold_amount || DEFAULT_DEPOSIT_THRESHOLD_AMOUNT,
    ),
    material: mapWorkOrderMaterial(workOrder.material_json),
    requirement: {
      fields: resolveRequirementFields(workOrder),
    },
    acceptance: mapAcceptanceForResponse(workOrder.acceptance_json),
    draftAcceptance: mapAcceptanceForResponse(workOrder.draft_acceptance_json),
    adminNote: workOrder.admin_note || '',
    problemNote: workOrder.problem_note || '',
    cancel:
      workOrder.status === WORK_ORDER_STATUS.CANCELLED
        ? {
            reason: String(workOrder.cancel_reason || ''),
            source: resolveWorkOrderCancelSource(workOrder.cancel_event_type),
            actorType: String(workOrder.cancel_actor_type || ''),
            actorName: String(workOrder.cancel_actor_id || ''),
            cancelledAt: workOrder.cancelled_at || null,
          }
        : null,
    worker: workOrder.assigned_worker_id
      ? {
          workerId: Number(workOrder.assigned_worker_id),
          username: workOrder.worker_username || '',
          displayName: workOrder.worker_display_name || '',
        }
      : null,
    ...(shares ? { sharingWorkers: mapWorkOrderSharingWorkers(shares) } : {}),
    publishedAt: workOrder.published_at,
    pinnedAt: workOrder.pinned_at,
    assignedAt: workOrder.assigned_at,
    submittedAt: workOrder.submitted_at,
    acceptedAt: workOrder.accepted_at,
    createdAt: workOrder.created_at,
    updatedAt: workOrder.updated_at,
  }
}

export function mapWorkOrderForWorker(
  workOrder: WorkOrderRow,
  permissions: { depositFreeAmount: number },
  myShare?: WorkOrderShareRow | null,
  workerNote = '',
  viewedAt?: string | null,
) {
  const mapped = mapWorkOrderAdmin(workOrder)
  const {
    requiredDepositAmount: _requiredDepositAmount,
    depositThresholdAmount: _depositThresholdAmount,
    worker: _worker,
    orderId: _orderId,
    orderItemId: _orderItemId,
    rawStatus: _rawStatus,
    hallAvailable: _hallAvailable,
    capabilities: _capabilities,
    adminNote: _adminNote,
    ...visibleOrder
  } = mapped
  const personalStatus = resolveWorkerShareStatus(workOrder.status, myShare?.status)
  return {
    ...visibleOrder,
    productName: myShare
      ? resolveWorkerShareProductName(workOrder.product_name, Number(myShare.quantity || 0))
      : visibleOrder.productName,
    status: personalStatus,
    rewardAmount: myShare ? Number(myShare.share_reward || 0) : visibleOrder.rewardAmount,
    freezeDepositAmount: myShare
      ? Number(myShare.share_deposit || 0)
      : resolveFreezeDepositAmount(workOrder, permissions),
    /** 用于大厅拼单按当前剩余份数准确计算个人免押后的押金。 */
    depositFreeAmount: Number(permissions.depositFreeAmount || 0),
    assignedAt: myShare?.created_at || visibleOrder.assignedAt,
    submittedAt: myShare?.submitted_at || visibleOrder.submittedAt,
    acceptedAt: myShare?.accepted_at || visibleOrder.acceptedAt,
    workerNote,
    myShare: myShare ? mapWorkOrderShare(myShare) : null,
    ...(viewedAt === undefined ? {} : { isUnread: !viewedAt }),
  }
}

/** 拼单参与者看到个人份额规格，而不是母工单的原始总规格。 */
export function resolveWorkerShareProductName(productName: unknown, quantity: number): string {
  const text = String(productName || '').trim()
  const normalizedQuantity = Math.max(1, Number(quantity) || 1)
  return text.replace(
    /(\d+|[零一二三四五六七八九十百千两]+)(\s*)(个|份|张|枚)/,
    (_matched, _oldQuantity: string, spacing: string, unit: string) =>
      `${normalizedQuantity}${spacing}${unit}`,
  )
}

/** 把份额状态映射成打手端订单状态，避免母工单 open 被误显示为已超时。 */
export function resolveWorkerShareStatus(workOrderStatus: string, shareStatus: unknown): string {
  if (!shareStatus) return workOrderStatus
  if (['accepted', 'cancelled', 'problem'].includes(workOrderStatus)) return workOrderStatus
  if (shareStatus === 'joined') return WORK_ORDER_STATUS.IN_PROGRESS
  if (shareStatus === 'submitted') return WORK_ORDER_STATUS.PENDING_ACCEPTANCE
  if (shareStatus === 'accepted') return WORK_ORDER_STATUS.ACCEPTED
  if (shareStatus === 'cancelled') return WORK_ORDER_STATUS.CANCELLED
  return workOrderStatus
}

export function mapWorkOrderShare(share: WorkOrderShareRow) {
  return {
    shareId: Number(share.id),
    workOrderId: Number(share.work_order_id),
    workerId: Number(share.worker_id),
    quantity: Number(share.quantity || 0),
    unitReward: Number(share.unit_reward || 0),
    shareReward: Number(share.share_reward || 0),
    shareDeposit: Number(share.share_deposit || 0),
    status: share.status,
    acceptance: mapAcceptanceForResponse(share.acceptance_json),
    draftAcceptance: mapAcceptanceForResponse(share.draft_acceptance_json),
    submittedAt: share.submitted_at,
    acceptedAt: share.accepted_at,
    createdAt: share.created_at,
    updatedAt: share.updated_at,
    worker: share.worker_id
      ? {
          workerId: Number(share.worker_id),
          username: share.worker_username || '',
          displayName: share.worker_display_name || share.worker_username || '',
        }
      : null,
  }
}

export function mapWorkOrderPublic(workOrder: WorkOrderRow) {
  return {
    workOrderId: Number(workOrder.id),
    workOrderNo: workOrder.work_order_no,
    platformOrderId: workOrder.platform_order_id,
    productName: workOrder.product_name,
    status: workOrder.status,
  }
}

export function mapCollectLookupOrder(workOrder: WorkOrderRow) {
  const material = mapWorkOrderMaterial(workOrder.material_json)
  return {
    ...mapWorkOrderPublic(workOrder),
    fields: resolveRequirementFields(workOrder),
    values: resolveCollectSubmittedFieldValues(workOrder),
    screenshots:
      material.collect && Array.isArray(material.collect.screenshots)
        ? material.collect.screenshots
        : [],
  }
}
