import { withTransaction } from '../../db/client.js'
import { isWorkOrderGiftDepositForfeitable } from '../../domain/work-order-acceptance-mode.js'
import { ensureWorkerWalletWithClient, getWorkerWalletWithClient } from './shared.js'
import { createWorkOrderEventWithClient } from './work-order-event-repo.js'
import { getWorkOrderByIdWithClient } from './work-order-query-repo.js'
import { getOutstandingDepositAmountWithClient } from './work-order-deposit-repo.js'
import { RESET_GIFT_FLOW_SQL } from './work-order-gift-repo.js'
import type { ProblemWorkOrderResolutionAction, WorkOrderRow } from './types.js'

/** 问题单退回打手时，按标记前状态恢复；异常历史数据回退单人单进行中。 */
export function resolveProblemReturnToWorkerStatus(
  fromStatus: string,
): 'open' | 'in_progress' | 'pending_acceptance' {
  if (['open', 'in_progress', 'pending_acceptance'].includes(fromStatus)) {
    return fromStatus as 'open' | 'in_progress' | 'pending_acceptance'
  }
  return 'in_progress'
}

export async function resolveProblemWorkOrder(input: {
  workOrderId: number
  action: ProblemWorkOrderResolutionAction
  note: string
  now: string
  actorName?: string
}): Promise<WorkOrderRow | null> {
  return withTransaction(async (client) => {
    const currentResult = await client.query<WorkOrderRow>(
      `
        SELECT *
        FROM work_orders
        WHERE id = $1
          AND status = 'problem'
        FOR UPDATE
      `,
      [input.workOrderId],
    )
    const workOrder = currentResult.rows[0] || null
    if (!workOrder) return null

    // return_to_worker 需恢复到标记问题单前的真实状态：拼单份额已全部提交时
    // 标记前是 pending_acceptance，若一律回到 in_progress 会陷入"份额已提交、
    // 母单却不可验收也不可重新提交"的卡死状态，因此按最近一次 marked_problem
    // 事件的 from_status 恢复。
    let restoreStatus = ''
    if (input.action === 'return_to_worker') {
      const eventResult = await client.query<{ from_status: string }>(
        `
          SELECT from_status
          FROM work_order_events
          WHERE work_order_id = $1 AND event_type = 'marked_problem'
          ORDER BY id DESC
          LIMIT 1
        `,
        [input.workOrderId],
      )
      const fromStatus = String(eventResult.rows[0]?.from_status || '').trim()
      restoreStatus = resolveProblemReturnToWorkerStatus(fromStatus)
    }

    // 赠送单已确认加好友后不再退押金：释放类处置转为扣除，事件类型按实际资金动作记录。
    const forfeitGiftDeposit = isWorkOrderGiftDepositForfeitable(workOrder)
    const releaseActions = ['reopen', 'cancel_release']
    const shouldReleaseDeposit = releaseActions.includes(input.action) && !forfeitGiftDeposit
    const shouldDeductDeposit =
      input.action === 'cancel_deduct' ||
      (releaseActions.includes(input.action) && forfeitGiftDeposit)
    const effectiveAction =
      input.action === 'cancel_release' && forfeitGiftDeposit ? 'cancel_deduct' : input.action
    const workerId = Number(workOrder.assigned_worker_id || 0)
    let resolvedDepositAmount = 0

    if (workerId > 0 && (shouldReleaseDeposit || shouldDeductDeposit)) {
      await ensureWorkerWalletWithClient(client, workerId, input.now)
      const wallet = await getWorkerWalletWithClient(client, workerId)
      resolvedDepositAmount = Math.min(
        await getOutstandingDepositAmountWithClient(client, workerId, input.workOrderId),
        Number(wallet?.frozen_deposit_amount || 0),
      )

      if (resolvedDepositAmount > 0) {
        const nextAvailable =
          Number(wallet?.available_amount || 0) + (shouldReleaseDeposit ? resolvedDepositAmount : 0)
        const nextFrozen = Math.max(
          0,
          Number(wallet?.frozen_deposit_amount || 0) - resolvedDepositAmount,
        )
        const ledgerType = shouldReleaseDeposit ? 'deposit_release' : 'deposit_deduction'
        const ledgerAmount = shouldReleaseDeposit ? resolvedDepositAmount : -resolvedDepositAmount
        const ledgerNote = shouldReleaseDeposit ? '问题单处置释放押金' : '问题单处置扣除押金'

        await client.query(
          `
            UPDATE worker_wallets
            SET available_amount = $1, frozen_deposit_amount = $2, updated_at = $3
            WHERE worker_id = $4
          `,
          [nextAvailable, nextFrozen, input.now, workerId],
        )
        await client.query(
          `
            INSERT INTO worker_wallet_ledgers (
              worker_id, ledger_type, amount, balance_after, frozen_after,
              related_work_order_id, note, payload_json, created_at
            ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9)
          `,
          [
            workerId,
            ledgerType,
            ledgerAmount,
            nextAvailable,
            nextFrozen,
            input.workOrderId,
            ledgerNote,
            JSON.stringify({ action: input.action, note: input.note }),
            input.now,
          ],
        )
      }
    }

    const targetStatus =
      input.action === 'return_to_worker'
        ? restoreStatus || 'in_progress'
        : input.action === 'reopen'
          ? 'open'
          : 'cancelled'
    const shouldClearAssignment = input.action === 'reopen'
    // 仅在真正退回打手重做（回到进行中）时清验收提交；份额已提交待验收的拼单
    // 需保留母单待验收状态，否则份额验收链路断裂。
    const shouldClearSubmission =
      input.action === 'reopen' ||
      (input.action === 'return_to_worker' && targetStatus === 'in_progress')

    await client.query(
      `
        UPDATE work_orders
        SET
          status = $1,
          assigned_worker_id = CASE WHEN $2 THEN NULL ELSE assigned_worker_id END,
          assigned_at = CASE WHEN $2 THEN NULL ELSE assigned_at END,
          acceptance_json = CASE WHEN $3 THEN '{}'::jsonb ELSE acceptance_json END,
          submitted_at = CASE WHEN $3 THEN NULL ELSE submitted_at END,
          problem_note = CASE WHEN $2 THEN '' ELSE problem_note END,
          deadline_at = CASE
            WHEN $1 = 'in_progress' AND timeout_minutes > 0 THEN
              CASE
                WHEN acceptance_mode = 'friend_gift'
                  AND gift_available_at IS NOT NULL
                  AND gift_available_at > NOW()
                THEN gift_available_at + (timeout_minutes * INTERVAL '1 minute')
                ELSE NOW() + (timeout_minutes * INTERVAL '1 minute')
              END
            WHEN $1 = 'open' THEN NULL
            ELSE deadline_at
          END,
          gift_phase = CASE
            WHEN $1 = 'open' OR $1 = 'cancelled'
              THEN CASE WHEN acceptance_mode = 'friend_gift' THEN 'material_required' ELSE '' END
            ELSE gift_phase
          END,
          booster_material_json = CASE
            WHEN $1 = 'open' OR $1 = 'cancelled' THEN '{}'::jsonb
            ELSE booster_material_json
          END,
          friend_added_at = CASE
            WHEN $1 = 'open' OR $1 = 'cancelled' THEN NULL
            ELSE friend_added_at
          END,
          gift_available_at = CASE
            WHEN $1 = 'open' OR $1 = 'cancelled' THEN NULL
            ELSE gift_available_at
          END,
          updated_at = $4
        WHERE id = $5
      `,
      [targetStatus, shouldClearAssignment, shouldClearSubmission, input.now, input.workOrderId],
    )

    await createWorkOrderEventWithClient(client, {
      workOrderId: input.workOrderId,
      actorType: 'admin',
      actorId: input.actorName || '',
      eventType: `problem_${effectiveAction}`,
      fromStatus: 'problem',
      toStatus: targetStatus,
      payloadJson: JSON.stringify({
        action: input.action,
        giftDepositForfeited: forfeitGiftDeposit || undefined,
        note: input.note,
        depositAmount: resolvedDepositAmount,
      }),
      now: input.now,
    })

    return getWorkOrderByIdWithClient(client, input.workOrderId)
  })
}

export async function settleOverdueWorkOrder(input: {
  workOrderId: number
  policy: 'reopen' | 'cancel_release' | 'cancel_deduct'
  now: string
}): Promise<{
  order: WorkOrderRow | null
  failureReason: 'work_order_not_overdue' | 'work_order_has_active_shares' | null
}> {
  return withTransaction(async (client) => {
    const currentResult = await client.query<WorkOrderRow>(
      `
        SELECT *
        FROM work_orders
        WHERE id = $1
          AND status = 'in_progress'
          AND deadline_at IS NOT NULL
          AND deadline_at < NOW()
        FOR UPDATE
      `,
      [input.workOrderId],
    )
    const workOrder = currentResult.rows[0] || null
    if (!workOrder) {
      return { order: null, failureReason: 'work_order_not_overdue' }
    }

    const shareResult = await client.query<{ total: number }>(
      `
        SELECT COUNT(*)::int AS total
        FROM work_order_shares
        WHERE work_order_id = $1 AND status != 'cancelled'
      `,
      [input.workOrderId],
    )
    if (Number(shareResult.rows[0]?.total || 0) > 0) {
      return { order: null, failureReason: 'work_order_has_active_shares' }
    }

    // 赠送单已确认加好友后不再退押金：释放类处置转为扣除，事件类型按实际资金动作记录。
    const forfeitGiftDeposit = isWorkOrderGiftDepositForfeitable(workOrder)
    const releasePolicies = ['reopen', 'cancel_release']
    const shouldReleaseDeposit = releasePolicies.includes(input.policy) && !forfeitGiftDeposit
    const shouldDeductDeposit =
      input.policy === 'cancel_deduct' ||
      (releasePolicies.includes(input.policy) && forfeitGiftDeposit)
    const effectivePolicy =
      input.policy === 'cancel_release' && forfeitGiftDeposit ? 'cancel_deduct' : input.policy
    const workerId = Number(workOrder.assigned_worker_id || 0)
    let resolvedDepositAmount = 0

    if (workerId > 0 && (shouldReleaseDeposit || shouldDeductDeposit)) {
      await ensureWorkerWalletWithClient(client, workerId, input.now)
      const wallet = await getWorkerWalletWithClient(client, workerId)
      resolvedDepositAmount = Math.min(
        await getOutstandingDepositAmountWithClient(client, workerId, input.workOrderId),
        Number(wallet?.frozen_deposit_amount || 0),
      )

      if (resolvedDepositAmount > 0) {
        const nextAvailable =
          Number(wallet?.available_amount || 0) + (shouldReleaseDeposit ? resolvedDepositAmount : 0)
        const nextFrozen = Math.max(
          0,
          Number(wallet?.frozen_deposit_amount || 0) - resolvedDepositAmount,
        )
        const ledgerType = shouldReleaseDeposit ? 'deposit_release' : 'deposit_deduction'
        const ledgerAmount = shouldReleaseDeposit ? resolvedDepositAmount : -resolvedDepositAmount
        const ledgerNote = shouldReleaseDeposit ? '超时处置释放押金' : '超时处置扣除押金'

        await client.query(
          `
            UPDATE worker_wallets
            SET available_amount = $1, frozen_deposit_amount = $2, updated_at = $3
            WHERE worker_id = $4
          `,
          [nextAvailable, nextFrozen, input.now, workerId],
        )
        await client.query(
          `
            INSERT INTO worker_wallet_ledgers (
              worker_id, ledger_type, amount, balance_after, frozen_after,
              related_work_order_id, note, payload_json, created_at
            ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9)
          `,
          [
            workerId,
            ledgerType,
            ledgerAmount,
            nextAvailable,
            nextFrozen,
            input.workOrderId,
            ledgerNote,
            JSON.stringify({ action: `timeout_${input.policy}` }),
            input.now,
          ],
        )
      }
    }

    const targetStatus = input.policy === 'reopen' ? 'open' : 'cancelled'

    await client.query(
      `
        UPDATE work_orders
        SET
          status = $1,
          assigned_worker_id = NULL,
          assigned_at = NULL,
          deadline_at = NULL,
          acceptance_json = CASE WHEN $1 = 'open' THEN '{}'::jsonb ELSE acceptance_json END,
          submitted_at = CASE WHEN $1 = 'open' THEN NULL ELSE submitted_at END,
          problem_note = CASE WHEN $1 = 'open' THEN '' ELSE problem_note END,
          published_at = CASE WHEN $1 = 'open' THEN $2 ELSE published_at END,
          hall_queued_at = CASE WHEN $1 = 'open' THEN $2 ELSE hall_queued_at END,
          ${RESET_GIFT_FLOW_SQL},
          updated_at = $2
        WHERE id = $3
      `,
      [targetStatus, input.now, input.workOrderId],
    )

    await createWorkOrderEventWithClient(client, {
      workOrderId: input.workOrderId,
      actorType: 'system',
      actorId: '',
      eventType: `timeout_${effectivePolicy}`,
      fromStatus: 'in_progress',
      toStatus: targetStatus,
      payloadJson: JSON.stringify({
        policy: input.policy,
        giftDepositForfeited: forfeitGiftDeposit || undefined,
        depositAmount: resolvedDepositAmount,
        workerId: workerId > 0 ? workerId : null,
      }),
      now: input.now,
    })

    return {
      order: await getWorkOrderByIdWithClient(client, input.workOrderId),
      failureReason: null,
    }
  })
}
