import { runtimeConfig } from '../../config/runtime.js'
import {
  createWorkerCancelRequest,
  createWorkerOrderFeedback,
  getLatestMaterialEventAtByOrderIds,
  getPendingCancelRequestOrderIds,
  getPendingFeedbackOrderIds,
  getWorkOrderShare,
  getWorkerCancelRequestRisk,
  getWorkerOrderOverview,
  listWorkerCancelRequests,
  listWorkerOrderFeedbacks,
  listWorkerSharesByWorker,
  listWorkerWorkOrderNotes,
  listWorkerWorkOrderViews,
  listWorkOrderEventsByOrderId,
  listWorkOrders,
  markWorkerWorkOrderViewed,
  upsertWorkerWorkOrderNote,
} 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 { normalizePage, normalizePageSize } from '../admin/admin-query-utils.js'
import { getWorkerAnnouncementConfig } from './worker-announcement-config-service.js'
import {
  createWorkerCancelRequestAdminNotification,
  createWorkerOrderFeedbackAdminNotification,
} from '../admin/admin-notification-service.js'
import { publishWorkOrderRealtimeChange } from '../realtime/realtime-event-service.js'
import {
  mapWorkOrderEvents,
  mapWorkOrderForWorker,
  mapWorkerCancelRequest,
  mapWorkerOrderFeedback,
  normalizeBoolean,
  normalizeStatuses,
  resolveWorkerPermissions,
} from './mappers.js'
import {
  getRequiredWorkOrder,
  getRequiredWorker,
  requireActiveWorkerSession,
  type WorkerSession,
} from './worker-session-context-service.js'
import { settleOverdueWorkOrders } from './worker-order-timeout-service.js'
import { WorkerListCache } from './worker-list-cache.js'

const MY_ORDER_LIST_CACHE_TTL_MS = 2_000
const myOrderListCache = new WorkerListCache(MY_ORDER_LIST_CACHE_TTL_MS)

export async function listWorkerMyOrders(query: JsonObject = {}, session: WorkerSession) {
  requireActiveWorkerSession(session)
  const worker = await getRequiredWorker(session.workerId)
  const page = normalizePage(query.page)
  const pageSize = normalizePageSize(query.pageSize)
  const vipEvidencePending = normalizeBoolean(query.vipEvidencePending, false)
  const permissions = resolveWorkerPermissions(worker)
  const statuses = normalizeStatuses(query.status)
  const keyword = String(query.keyword || '').trim()
  const cacheKey = JSON.stringify([
    worker.id,
    page,
    pageSize,
    statuses,
    keyword,
    vipEvidencePending,
  ])
  return myOrderListCache.getOrSet(cacheKey, async () => {
    const { items, total } = await listWorkOrders({
      page,
      pageSize,
      statuses,
      keyword,
      workerSharingId: worker.id,
      vipEvidencePending,
      sort: 'worker_claimed_at_desc',
    })
    const workOrderIds = items.map((item) => Number(item.id))
    const myShares = await listWorkerSharesByWorker(worker.id, workOrderIds)
    const myShareByOrderId = new Map(myShares.map((share) => [Number(share.work_order_id), share]))
    const [notes, views, pendingCancelOrderIds, pendingFeedbackOrderIds, materialEventAtByOrderId] =
      await Promise.all([
        listWorkerWorkOrderNotes(worker.id, workOrderIds),
        listWorkerWorkOrderViews(worker.id, workOrderIds),
        getPendingCancelRequestOrderIds(worker.id, workOrderIds),
        getPendingFeedbackOrderIds(worker.id, workOrderIds),
        getLatestMaterialEventAtByOrderIds(workOrderIds),
      ])
    const noteByOrderId = new Map(
      notes.map((item) => [Number(item.work_order_id), String(item.note || '')]),
    )
    const viewedAtByOrderId = new Map(
      views.map((item) => [Number(item.work_order_id), String(item.viewed_at || '')]),
    )
    const materialSeenAtByOrderId = new Map(
      views.map((item) => [Number(item.work_order_id), String(item.material_seen_at || '')]),
    )
    return {
      items: items.map((item) => {
        const workOrderId = Number(item.id)
        const materialEventAt = materialEventAtByOrderId.get(workOrderId) || ''
        const materialSeenAt = materialSeenAtByOrderId.get(workOrderId) || ''
        const materialUpdated =
          Boolean(materialEventAt) &&
          (!materialSeenAt ||
            new Date(materialEventAt).getTime() > new Date(materialSeenAt).getTime())
        return {
          ...mapWorkOrderForWorker(
            item,
            permissions,
            myShareByOrderId.get(workOrderId),
            noteByOrderId.get(workOrderId) || '',
            viewedAtByOrderId.get(workOrderId) || null,
          ),
          // 问题单分组内的来源角标：平台标记 / 退单审核中 / 反馈处理中。
          problemMarked: item.status === 'problem',
          pendingCancelRequest: pendingCancelOrderIds.has(workOrderId),
          pendingFeedback: pendingFeedbackOrderIds.has(workOrderId),
          materialUpdated,
        }
      }),
      pagination: { page, pageSize, total },
    }
  })
}

/** 打手订单标签概览：订单数与预计或已结算金额。 */
export async function getWorkerMyOrderOverview(session: WorkerSession) {
  requireActiveWorkerSession(session)
  const worker = await getRequiredWorker(session.workerId)
  await settleOverdueWorkOrders({ workerId: worker.id, limit: 50 })
  const rows = await getWorkerOrderOverview(worker.id)
  const items = rows.map((row) => ({
    status: row.status,
    orderCount: row.orderCount,
    settlementAmount: row.settlementAmount,
  }))
  const vipEvidencePending = rows.reduce(
    (summary, row) => ({
      orderCount: summary.orderCount + row.vipEvidencePendingCount,
      settlementAmount: summary.settlementAmount + row.vipEvidencePendingSettlementAmount,
    }),
    { orderCount: 0, settlementAmount: 0 },
  )
  const all = items.reduce(
    (summary, item) => ({
      orderCount: summary.orderCount + item.orderCount,
      settlementAmount: summary.settlementAmount + item.settlementAmount,
    }),
    { orderCount: 0, settlementAmount: 0 },
  )
  return {
    items: [
      ...items,
      { status: 'vip_evidence_pending', ...vipEvidencePending },
      { status: 'all', ...all },
    ],
  }
}

export async function getWorkerMyOrderEvents(workOrderId: number | string, session: WorkerSession) {
  requireActiveWorkerSession(session)
  if (runtimeConfig.worker.orderTimelineVisible !== true) {
    throw createHttpError('流转记录暂未对打手开放', {
      statusCode: 403,
      errorCode: 'work_order_events_worker_disabled',
    })
  }
  const workOrder = await getRequiredWorkOrder(workOrderId)
  const workerId = Number(session.workerId)
  const sharingShare = await getWorkOrderShare(workOrder.id, workerId)
  const isOrderOwner =
    Number(workOrder.assigned_worker_id || 0) === workerId ||
    Number(workOrder.last_assigned_worker_id || 0) === workerId
  if (!sharingShare && !isOrderOwner) {
    throw createHttpError('只能查看自己订单的流转记录', {
      statusCode: 403,
      errorCode: 'work_order_events_owner_required',
    })
  }
  const events = await listWorkOrderEventsByOrderId(workOrderId)
  return { items: await mapWorkOrderEvents(events) }
}

export async function getWorkerCancelRequestSummary(session: WorkerSession) {
  requireActiveWorkerSession(session)
  const [risk, requests] = await Promise.all([
    getWorkerCancelRequestRisk(session.workerId, nowIso()),
    listWorkerCancelRequests(session.workerId),
  ])
  return { risk, items: requests.map(mapWorkerCancelRequest) }
}

export async function getWorkerAnnouncement(session: WorkerSession) {
  requireActiveWorkerSession(session)
  return getWorkerAnnouncementConfig()
}

export async function getWorkerOrderFeedbackSummary(session: WorkerSession) {
  requireActiveWorkerSession(session)
  return { items: (await listWorkerOrderFeedbacks(session.workerId)).map(mapWorkerOrderFeedback) }
}

export async function submitWorkerOrderFeedback(
  workOrderId: number | string,
  payload: JsonObject = {},
  session: WorkerSession,
) {
  requireActiveWorkerSession(session)
  const content = String(payload.content || '').trim()
  if (!content) {
    throw createHttpError('请填写问题反馈内容', {
      statusCode: 400,
      errorCode: 'worker_order_feedback_content_required',
    })
  }
  if (content.length > 500) {
    throw createHttpError('问题反馈不能超过 500 个字符', {
      statusCode: 400,
      errorCode: 'worker_order_feedback_content_too_long',
    })
  }
  const result = await createWorkerOrderFeedback({
    workOrderId: Number(workOrderId),
    workerId: Number(session.workerId),
    content,
    now: nowIso(),
  })
  if (!result.feedback) {
    throw createHttpError('只能反馈自己的订单问题', {
      statusCode: 403,
      errorCode: 'worker_order_feedback_owner_required',
    })
  }
  const worker = await getRequiredWorker(session.workerId)
  await createWorkerOrderFeedbackAdminNotification({
    feedbackId: Number(result.feedback.id),
    workOrderId: Number(result.feedback.work_order_id),
    workOrderNo: result.feedback.work_order_no || '',
    productName: result.feedback.product_name || '',
    workerName: worker.display_name || worker.username,
    content,
  })
  publishWorkOrderRealtimeChange({
    workOrderId: Number(result.feedback.work_order_id),
    workerIds: [Number(session.workerId)],
  })
  return { feedback: mapWorkerOrderFeedback(result.feedback) }
}

export async function submitWorkerCancelRequest(
  workOrderId: number | string,
  payload: JsonObject = {},
  session: WorkerSession,
) {
  requireActiveWorkerSession(session)
  const reason = String(payload.reason || '').trim()
  if (!reason) {
    throw createHttpError('请填写申请取消原因', {
      statusCode: 400,
      errorCode: 'worker_cancel_request_reason_required',
    })
  }
  if (reason.length > 300) {
    throw createHttpError('申请取消原因不能超过 300 个字符', {
      statusCode: 400,
      errorCode: 'worker_cancel_request_reason_too_long',
    })
  }
  const now = nowIso()
  const result = await createWorkerCancelRequest({
    workOrderId: Number(workOrderId),
    workerId: Number(session.workerId),
    reason,
    now,
  })
  if (result.failureReason === 'daily_limit_reached') {
    throw createHttpError('今日最多申请取消 5 次，请明日再试', {
      statusCode: 429,
      errorCode: 'worker_cancel_request_daily_limit',
    })
  }
  if (result.failureReason === 'request_pending') {
    throw createHttpError('该订单已有待审核的取消申请', {
      statusCode: 409,
      errorCode: 'worker_cancel_request_pending',
    })
  }
  if (result.failureReason === 'share_not_cancellable') {
    throw createHttpError('当前拼单份额不能申请取消', {
      statusCode: 409,
      errorCode: 'worker_cancel_request_share_status_invalid',
    })
  }
  if (!result.request) {
    throw createHttpError('当前订单不能申请取消', {
      statusCode: 409,
      errorCode: 'worker_cancel_request_status_invalid',
    })
  }
  const worker = await getRequiredWorker(session.workerId)
  await createWorkerCancelRequestAdminNotification({
    requestId: Number(result.request.id),
    workOrderId: Number(result.request.work_order_id),
    platformOrderId: result.request.platform_order_id || '',
    productName: result.request.product_name || '',
    workerName: worker.display_name || worker.username,
    reason,
  })
  const risk = await getWorkerCancelRequestRisk(session.workerId, now)
  publishWorkOrderRealtimeChange({
    workOrderId: Number(result.request.work_order_id),
    workerIds: [Number(session.workerId)],
  })
  return { request: mapWorkerCancelRequest(result.request), risk }
}

export async function saveWorkerOrderNote(
  workOrderId: number | string,
  payload: JsonObject = {},
  session: WorkerSession,
) {
  requireActiveWorkerSession(session)
  const workOrder = await getRequiredWorkOrder(workOrderId)
  const workerId = Number(session.workerId)
  const note = String(payload.note || '').trim()
  if (note.length > 100) {
    throw createHttpError('备注不能超过 100 个字符', {
      statusCode: 400,
      errorCode: 'work_order_note_too_long',
    })
  }

  const worker = await getRequiredWorker(workerId)
  const sharingShare = await getWorkOrderShare(workOrder.id, workerId)
  const isOrderOwner =
    Number(workOrder.assigned_worker_id || 0) === workerId ||
    Number(workOrder.last_assigned_worker_id || 0) === workerId
  if (!sharingShare && !isOrderOwner) {
    throw createHttpError('只能修改自己的订单备注', {
      statusCode: 403,
      errorCode: 'work_order_note_owner_required',
    })
  }
  const savedNote = await upsertWorkerWorkOrderNote({
    workOrderId: Number(workOrder.id),
    workerId,
    note,
    now: nowIso(),
  })
  return {
    order: mapWorkOrderForWorker(
      workOrder,
      resolveWorkerPermissions(worker),
      sharingShare,
      savedNote,
    ),
  }
}

/** 标记打手本人已查看工单，首次操作后不再展示“新”标识；materialSeen 同时刷新资料查看时间。 */
export async function markWorkerOrderRead(
  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)
  const isOrderOwner =
    Number(workOrder.assigned_worker_id || 0) === workerId ||
    Number(workOrder.last_assigned_worker_id || 0) === workerId
  if (!sharingShare && !isOrderOwner) {
    throw createHttpError('只能标记自己的订单为已读', {
      statusCode: 403,
      errorCode: 'work_order_read_owner_required',
    })
  }

  const viewedAt = await markWorkerWorkOrderViewed({
    workOrderId: Number(workOrder.id),
    workerId,
    now: nowIso(),
    materialSeen: payload.materialSeen === true || payload.materialSeen === 'true',
  })
  publishWorkOrderRealtimeChange({
    workOrderId: Number(workOrder.id),
    workerIds: [workerId],
  })
  return { viewedAt, isUnread: false }
}
