import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
import {
  assignWorkOrderToWorker,
  countWorkerActiveOrders,
  createWorkOrderEvent,
  getWorkerUserById,
} from '../../repositories/worker-platform/index.js'
import type { JsonObject } from '../../types/json.js'
import { createHttpError } from '../../utils/http.js'
import { nowIso } from '../../utils/time.js'
import {
  publishWorkerWalletRealtimeChange,
  publishWorkOrderRealtimeChange,
} from '../realtime/realtime-event-service.js'
import { consumeIndustryVouchersBeforeWorkOrderAssign } from './publish-voucher-service.js'
import {
  mapWorkOrderAdmin,
  normalizeOptionalId,
  resolveFreezeDepositAmount,
  resolveWorkerPermissions,
} from './mappers.js'
import { getRequiredWorkOrder } from './worker-session-context-service.js'

export async function assignAdminWorkOrderToWorker(
  workOrderId: number | string,
  payload: JsonObject = {},
  actorName = '',
) {
  const workOrder = await getRequiredWorkOrder(workOrderId)
  const capabilities = mapWorkOrderAdmin(workOrder).capabilities
  if (!capabilities.canAssign) {
    throw createHttpError('只有未分配或待抢单且未指派打手的订单才能指派', {
      statusCode: 409,
      errorCode: 'work_order_not_assignable',
    })
  }
  const workerId = normalizeOptionalId(payload.workerId ?? payload.worker_id)
  if (!workerId) {
    throw createHttpError('请选择要指派的打手', {
      statusCode: 400,
      errorCode: 'work_order_assign_worker_required',
    })
  }
  const worker = await getWorkerUserById(workerId)
  if (!worker || worker.status !== 'active') {
    throw createHttpError('打手账号不存在或不可用', {
      statusCode: 409,
      errorCode: 'work_order_assign_worker_invalid',
    })
  }
  const permissions = resolveWorkerPermissions(worker)
  const activeCount = await countWorkerActiveOrders(worker.id)
  if (activeCount >= permissions.maxActiveOrders) {
    throw createHttpError('该打手已达到最大同时接单量', {
      statusCode: 409,
      errorCode: 'worker_active_order_limit',
    })
  }
  const freezeAmount = resolveFreezeDepositAmount(workOrder, permissions)
  if (Number(worker.available_amount || 0) < freezeAmount) {
    throw createHttpError('该打手余额不足，无法冻结所需押金', {
      statusCode: 409,
      errorCode: 'worker_deposit_insufficient',
    })
  }

  const voucherConsume = await consumeIndustryVouchersBeforeWorkOrderAssign(workOrder)
  if (!voucherConsume.ok) {
    const failedAt = nowIso()
    await createWorkOrderEvent({
      workOrderId: workOrder.id,
      actorType: 'admin',
      actorId: actorName,
      eventType: 'assign_voucher_consume_failed',
      fromStatus: workOrder.status,
      toStatus: workOrder.status,
      payloadJson: JSON.stringify({ workerId: worker.id, voucherConsume }),
      now: failedAt,
    })
    throw createHttpError(voucherConsume.errorMessage || '电子凭证核销失败，订单未指派', {
      statusCode: 409,
      errorCode: 'work_order_assign_voucher_consume_failed',
      context: voucherConsume,
    })
  }

  const now = nowIso()
  const { order: updated, failureReason } = await assignWorkOrderToWorker({
    workOrderId: workOrder.id,
    workerId: worker.id,
    depositAmount: freezeAmount,
    maxActiveOrders: permissions.maxActiveOrders,
    deadlineAt: resolveAssignedDeadlineAt(Number(workOrder.timeout_minutes || 0), now),
    now,
    actorName,
  })
  if (failureReason === 'work_order_not_assignable') {
    throw createHttpError(
      resolveAssignFailureMessage(voucherConsume.voucherCount, '订单状态已变化，无法指派'),
      { statusCode: 409, errorCode: 'work_order_not_assignable' },
    )
  }
  if (failureReason === 'worker_active_order_limit') {
    throw createHttpError(
      resolveAssignFailureMessage(voucherConsume.voucherCount, '该打手已达到最大同时接单量'),
      { statusCode: 409, errorCode: 'worker_active_order_limit' },
    )
  }
  if (failureReason === 'worker_deposit_insufficient') {
    throw createHttpError(
      resolveAssignFailureMessage(voucherConsume.voucherCount, '该打手余额不足，无法冻结所需押金'),
      { statusCode: 409, errorCode: 'worker_deposit_insufficient' },
    )
  }
  if (!updated) {
    throw createHttpError(
      resolveAssignFailureMessage(voucherConsume.voucherCount, '指派失败，订单状态可能已变化'),
      { statusCode: 409, errorCode: 'work_order_assign_conflict' },
    )
  }
  publishWorkOrderRealtimeChange({
    workOrderId: Number(workOrder.id),
    workerIds: [Number(worker.id)],
    hallChanged: workOrder.status === WORK_ORDER_STATUS.OPEN,
  })
  publishWorkerWalletRealtimeChange(Number(worker.id))
  return { order: mapWorkOrderAdmin(updated), voucherConsume }
}

function resolveAssignFailureMessage(voucherCount: number, fallback: string) {
  return voucherCount > 0 ? `电子凭证已核销，但${fallback}，请重试指派` : fallback
}

function resolveAssignedDeadlineAt(timeoutMinutes: number, now: string): string | null {
  if (timeoutMinutes <= 0) return null
  return new Date(new Date(now).getTime() + timeoutMinutes * 60 * 1000).toISOString()
}
