import { withTransaction } from '../../db/client.js'
import { offsetWorkerAfterSalesDebtsWithClient } from './after-sales-repo.js'
import {
  ensureWorkerWalletWithClient,
  getWorkerWalletWithClient,
  WORK_ORDER_SHARE_SELECT,
  resolveWorkOrderShareCancellationStatus,
  resolveWorkOrderSharingCancellationPlan,
} from './shared.js'
import { createWorkOrderEventWithClient } from './work-order-event-repo.js'
import { getWorkOrderByIdWithClient } from './work-order-query-repo.js'
import {
  enqueueDepositUnfreezeWithClient,
  getOutstandingDepositAmountWithClient,
} from './work-order-deposit-repo.js'
import { maybeUpgradeWorkerLevelWithClient } from './worker-ranking-repo.js'
import type { WorkOrderRow, WorkOrderShareRow } from './types.js'

export async function acceptWorkOrderAndSettle(input: {
  workOrderId: number
  unfreezeDays: number
  rewardUnfreezeEnabled: boolean
  now: string
  /** 操作人类型：admin / worker / system */
  actorType?: string
  /** 操作人显示名 */
  actorName?: string
}): Promise<{
  order: WorkOrderRow | null
  failureReason: 'sharing_pending_submissions' | null
}> {
  return withTransaction(async (client) => {
    const currentResult = await client.query<WorkOrderRow>(
      `
        SELECT *
        FROM work_orders
        WHERE id = $1
          AND status = 'pending_acceptance'
        FOR UPDATE
      `,
      [input.workOrderId],
    )
    const workOrder = currentResult.rows[0] || null
    if (!workOrder) {
      return { order: null, failureReason: null }
    }

    const sharesResult = await client.query<WorkOrderShareRow>(
      `
        SELECT *
        FROM work_order_shares
        WHERE work_order_id = $1
          AND status != 'cancelled'
        ORDER BY id ASC
        FOR UPDATE
      `,
      [input.workOrderId],
    )
    const shares = sharesResult.rows
    if (shares.length > 0) {
      const pendingShares = shares.filter((share) => share.status === 'joined')
      if (pendingShares.length > 0) {
        return {
          order: null,
          failureReason: 'sharing_pending_submissions',
        }
      }
    }

    await client.query(
      `
        UPDATE work_orders
        SET status = 'accepted', accepted_at = $1, updated_at = $1
        WHERE id = $2
      `,
      [input.now, input.workOrderId],
    )

    if (shares.length > 0) {
      // 单独验收过的份额已经完成资金结算，统一验收时只处理尚未结算的份额。
      const unsettledShares = shares.filter((share) => share.status !== 'accepted')
      for (const share of unsettledShares) {
        const shareWorkerId = Number(share.worker_id || 0)
        if (!shareWorkerId) continue
        await ensureWorkerWalletWithClient(client, shareWorkerId, input.now)
        const wallet = await getWorkerWalletWithClient(client, shareWorkerId)
        const releaseAmount = Math.min(
          Number(share.share_deposit || 0),
          Number(wallet?.frozen_deposit_amount || 0),
        )
        const shareReward = Number(share.share_reward || 0)
        const debtOffsets = await offsetWorkerAfterSalesDebtsWithClient(client, {
          workerId: shareWorkerId,
          amount: shareReward,
          workOrderId: input.workOrderId,
          now: input.now,
        })
        const debtOffsetAmount = debtOffsets.reduce((total, item) => total + item.amount, 0)
        const shouldDelayUnfreeze = input.rewardUnfreezeEnabled && input.unfreezeDays > 0
        const pendingUnfreezeAmount =
          (shouldDelayUnfreeze ? shareReward : 0) + (input.unfreezeDays > 0 ? releaseAmount : 0)
        const nextAvailable =
          Number(wallet?.available_amount || 0) +
          (shouldDelayUnfreeze ? 0 : shareReward) +
          (input.unfreezeDays > 0 ? 0 : releaseAmount) -
          debtOffsetAmount
        const nextFrozen = Math.max(0, Number(wallet?.frozen_deposit_amount || 0) - releaseAmount)

        await client.query(
          `
            UPDATE worker_wallets
            SET
              available_amount = $1,
              frozen_deposit_amount = $2,
              pending_unfreeze_amount = pending_unfreeze_amount + $3,
              total_settled_amount = total_settled_amount + $4,
              updated_at = $5
            WHERE worker_id = $6
          `,
          [nextAvailable, nextFrozen, pendingUnfreezeAmount, shareReward, input.now, shareWorkerId],
        )

        if (releaseAmount > 0 && input.unfreezeDays > 0) {
          await enqueueDepositUnfreezeWithClient(client, {
            workerId: shareWorkerId,
            workOrderId: input.workOrderId,
            amount: releaseAmount,
            fundType: 'deposit',
            unfreezeDays: input.unfreezeDays,
            now: input.now,
          })
        }
        if (shareReward > 0 && shouldDelayUnfreeze) {
          await enqueueDepositUnfreezeWithClient(client, {
            workerId: shareWorkerId,
            workOrderId: input.workOrderId,
            amount: shareReward,
            fundType: 'reward',
            unfreezeDays: input.unfreezeDays,
            now: input.now,
          })
        }
        if (releaseAmount > 0 && input.unfreezeDays > 0) {
          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, 'deposit_pending_unfreeze', $2, $3, $4, $5, '拼单验收押金待解冻', $6::jsonb, $7)
              `,
            [
              shareWorkerId,
              releaseAmount,
              nextAvailable,
              nextFrozen,
              input.workOrderId,
              JSON.stringify({
                workOrderId: input.workOrderId,
                shareId: Number(share.id),
                unfreezeDays: input.unfreezeDays,
              }),
              input.now,
            ],
          )
        }
        if (releaseAmount > 0 && input.unfreezeDays === 0) {
          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, 'deposit_release', $2, $3, $4, $5, '拼单验收释放押金', $6::jsonb, $7)
            `,
            [
              shareWorkerId,
              releaseAmount,
              nextAvailable,
              nextFrozen,
              input.workOrderId,
              JSON.stringify({ workOrderId: input.workOrderId, shareId: Number(share.id) }),
              input.now,
            ],
          )
        }

        if (shareReward > 0) {
          const rewardLedgerType = shouldDelayUnfreeze
            ? 'reward_pending_unfreeze'
            : 'reward_settlement'
          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)
            `,
            [
              shareWorkerId,
              rewardLedgerType,
              shareReward,
              nextAvailable,
              nextFrozen,
              input.workOrderId,
              shouldDelayUnfreeze
                ? '拼单份额验收报酬待解冻'
                : `拼单份额验收结算报酬 ${share.quantity} 份`,
              JSON.stringify({
                workOrderId: input.workOrderId,
                shareId: Number(share.id),
                quantity: share.quantity,
                ...(shouldDelayUnfreeze ? { unfreezeDays: input.unfreezeDays } : {}),
              }),
              input.now,
            ],
          )
        }
        for (const debtOffset of debtOffsets) {
          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, 'after_sales_debt_offset', $2, $3, $4, $5, '验收报酬自动抵扣售后欠款', $6::jsonb, $7)
            `,
            [
              shareWorkerId,
              -debtOffset.amount,
              nextAvailable,
              nextFrozen,
              input.workOrderId,
              JSON.stringify({
                caseId: debtOffset.caseId,
                workOrderId: input.workOrderId,
                shareId: Number(share.id),
              }),
              input.now,
            ],
          )
        }

        await client.query(
          `
            UPDATE work_order_shares
            SET status = 'accepted', accepted_at = $1, updated_at = $1
            WHERE id = $2
          `,
          [input.now, Number(share.id)],
        )
        await maybeUpgradeWorkerLevelWithClient(client, shareWorkerId, input.now)
      }
    }

    const workerId = Number(workOrder.assigned_worker_id || 0)
    if (workerId > 0) {
      await ensureWorkerWalletWithClient(client, workerId, input.now)
      const wallet = await getWorkerWalletWithClient(client, workerId)
      const releaseAmount = Math.min(
        await getOutstandingDepositAmountWithClient(client, workerId, input.workOrderId),
        Number(wallet?.frozen_deposit_amount || 0),
      )
      const rewardAmount = Number(workOrder.reward_amount || 0)
      const debtOffsets = await offsetWorkerAfterSalesDebtsWithClient(client, {
        workerId,
        amount: rewardAmount,
        workOrderId: input.workOrderId,
        now: input.now,
      })
      const debtOffsetAmount = debtOffsets.reduce((total, item) => total + item.amount, 0)
      const shouldDelayUnfreeze = input.rewardUnfreezeEnabled && input.unfreezeDays > 0
      const pendingUnfreezeAmount =
        (shouldDelayUnfreeze ? rewardAmount : 0) + (input.unfreezeDays > 0 ? releaseAmount : 0)
      const nextAvailable =
        Number(wallet?.available_amount || 0) +
        (shouldDelayUnfreeze ? 0 : rewardAmount) +
        (input.unfreezeDays > 0 ? 0 : releaseAmount) -
        debtOffsetAmount
      const nextFrozen = Math.max(0, Number(wallet?.frozen_deposit_amount || 0) - releaseAmount)

      await client.query(
        `
          UPDATE worker_wallets
          SET
            available_amount = $1,
            frozen_deposit_amount = $2,
            pending_unfreeze_amount = pending_unfreeze_amount + $3,
            total_settled_amount = total_settled_amount + $4,
            updated_at = $5
          WHERE worker_id = $6
        `,
        [nextAvailable, nextFrozen, pendingUnfreezeAmount, rewardAmount, input.now, workerId],
      )

      if (releaseAmount > 0 && input.unfreezeDays > 0) {
        await enqueueDepositUnfreezeWithClient(client, {
          workerId,
          workOrderId: input.workOrderId,
          amount: releaseAmount,
          fundType: 'deposit',
          unfreezeDays: input.unfreezeDays,
          now: input.now,
        })
      }
      if (rewardAmount > 0 && shouldDelayUnfreeze) {
        await enqueueDepositUnfreezeWithClient(client, {
          workerId,
          workOrderId: input.workOrderId,
          amount: rewardAmount,
          fundType: 'reward',
          unfreezeDays: input.unfreezeDays,
          now: input.now,
        })
      }

      if (releaseAmount > 0) {
        if (input.unfreezeDays > 0) {
          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, 'deposit_pending_unfreeze', $2, $3, $4, $5, '验收通过押金待解冻', $6::jsonb, $7)
            `,
            [
              workerId,
              releaseAmount,
              nextAvailable,
              nextFrozen,
              input.workOrderId,
              JSON.stringify({
                workOrderId: input.workOrderId,
                unfreezeDays: input.unfreezeDays,
              }),
              input.now,
            ],
          )
        } else {
          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, 'deposit_release', $2, $3, $4, $5, '验收通过释放押金', '{}'::jsonb, $6)
            `,
            [workerId, releaseAmount, nextAvailable, nextFrozen, input.workOrderId, input.now],
          )
        }
      }

      if (rewardAmount > 0) {
        const rewardLedgerType = shouldDelayUnfreeze
          ? 'reward_pending_unfreeze'
          : 'reward_settlement'
        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,
            rewardLedgerType,
            rewardAmount,
            nextAvailable,
            nextFrozen,
            input.workOrderId,
            shouldDelayUnfreeze ? '验收通过报酬待解冻' : '验收通过结算报酬',
            JSON.stringify(
              shouldDelayUnfreeze
                ? { workOrderId: input.workOrderId, unfreezeDays: input.unfreezeDays }
                : {},
            ),
            input.now,
          ],
        )
      }
      for (const debtOffset of debtOffsets) {
        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, 'after_sales_debt_offset', $2, $3, $4, $5, '验收报酬自动抵扣售后欠款', $6::jsonb, $7)
          `,
          [
            workerId,
            -debtOffset.amount,
            nextAvailable,
            nextFrozen,
            input.workOrderId,
            JSON.stringify({ caseId: debtOffset.caseId, workOrderId: input.workOrderId }),
            input.now,
          ],
        )
      }
    }

    await createWorkOrderEventWithClient(client, {
      workOrderId: input.workOrderId,
      actorType: input.actorType || 'admin',
      actorId: input.actorName || '',
      eventType: 'accepted',
      fromStatus: 'pending_acceptance',
      toStatus: 'accepted',
      payloadJson: JSON.stringify({
        shareCount: shares.length,
        settledShareCount: shares.filter((share) => share.status !== 'accepted').length,
      }),
      now: input.now,
    })

    if (workerId > 0) {
      await maybeUpgradeWorkerLevelWithClient(client, workerId, input.now)
    }

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

/** 单独验收一个拼单份额，只结算该参与者，不影响其他份额。 */
export async function acceptWorkOrderShareAndSettle(input: {
  workOrderId: number
  shareId: number
  unfreezeDays: number
  rewardUnfreezeEnabled: boolean
  now: string
  actorType?: string
  actorName?: string
}): Promise<{
  order: WorkOrderRow | null
  share: WorkOrderShareRow | null
  failureReason: 'work_order_not_accepting' | 'share_not_submitted' | null
}> {
  return withTransaction(async (client) => {
    // in_progress 仅用于解围历史问题单处置产生的"份额已提交、母单却回到进行中"
    // 的卡死存量单；正常拼单流程母单只会是 open / pending_acceptance。
    const orderResult = await client.query<WorkOrderRow>(
      `SELECT * FROM work_orders WHERE id = $1 AND status IN ('open', 'pending_acceptance', 'in_progress') FOR UPDATE`,
      [input.workOrderId],
    )
    const workOrder = orderResult.rows[0] || null
    if (!workOrder) {
      return { order: null, share: null, failureReason: 'work_order_not_accepting' }
    }

    const shareResult = await client.query<WorkOrderShareRow>(
      `SELECT * FROM work_order_shares WHERE id = $1 AND work_order_id = $2 FOR UPDATE`,
      [input.shareId, input.workOrderId],
    )
    const share = shareResult.rows[0] || null
    if (!share || share.status !== 'submitted') {
      return { order: workOrder, share, failureReason: 'share_not_submitted' }
    }

    const workerId = Number(share.worker_id || 0)
    if (workerId > 0) {
      await ensureWorkerWalletWithClient(client, workerId, input.now)
      const wallet = await getWorkerWalletWithClient(client, workerId)
      const releaseAmount = Math.min(
        Number(share.share_deposit || 0),
        Number(wallet?.frozen_deposit_amount || 0),
      )
      const shareReward = Number(share.share_reward || 0)
      const debtOffsets = await offsetWorkerAfterSalesDebtsWithClient(client, {
        workerId,
        amount: shareReward,
        workOrderId: input.workOrderId,
        now: input.now,
      })
      const debtOffsetAmount = debtOffsets.reduce((total, item) => total + item.amount, 0)
      const shouldDelayUnfreeze = input.rewardUnfreezeEnabled && input.unfreezeDays > 0
      const pendingUnfreezeAmount =
        (shouldDelayUnfreeze ? shareReward : 0) + (input.unfreezeDays > 0 ? releaseAmount : 0)
      const nextAvailable =
        Number(wallet?.available_amount || 0) +
        (shouldDelayUnfreeze ? 0 : shareReward) +
        (input.unfreezeDays > 0 ? 0 : releaseAmount) -
        debtOffsetAmount
      const nextFrozen = Math.max(0, Number(wallet?.frozen_deposit_amount || 0) - releaseAmount)
      await client.query(
        `UPDATE worker_wallets
         SET available_amount = $1, frozen_deposit_amount = $2,
             pending_unfreeze_amount = pending_unfreeze_amount + $3,
             total_settled_amount = total_settled_amount + $4, updated_at = $5
         WHERE worker_id = $6`,
        [nextAvailable, nextFrozen, pendingUnfreezeAmount, shareReward, input.now, workerId],
      )

      if (releaseAmount > 0 && input.unfreezeDays > 0) {
        await enqueueDepositUnfreezeWithClient(client, {
          workerId,
          workOrderId: input.workOrderId,
          amount: releaseAmount,
          fundType: 'deposit',
          unfreezeDays: input.unfreezeDays,
          now: input.now,
        })
      }
      if (shareReward > 0 && shouldDelayUnfreeze) {
        await enqueueDepositUnfreezeWithClient(client, {
          workerId,
          workOrderId: input.workOrderId,
          amount: shareReward,
          fundType: 'reward',
          unfreezeDays: input.unfreezeDays,
          now: input.now,
        })
      }
      if (releaseAmount > 0) {
        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,
            input.unfreezeDays > 0 ? 'deposit_pending_unfreeze' : 'deposit_release',
            releaseAmount,
            nextAvailable,
            nextFrozen,
            input.workOrderId,
            input.unfreezeDays > 0 ? '拼单份额验收押金待解冻' : '拼单份额验收释放押金',
            JSON.stringify({ workOrderId: input.workOrderId, shareId: input.shareId }),
            input.now,
          ],
        )
      }
      if (shareReward > 0) {
        const rewardLedgerType = shouldDelayUnfreeze ? 'reward_pending_unfreeze' : 'sharing_reward'
        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,
            rewardLedgerType,
            shareReward,
            nextAvailable,
            nextFrozen,
            input.workOrderId,
            shouldDelayUnfreeze
              ? '拼单份额验收报酬待解冻'
              : `拼单份额验收结算报酬 ${share.quantity} 份`,
            JSON.stringify(
              shouldDelayUnfreeze
                ? {
                    workOrderId: input.workOrderId,
                    shareId: input.shareId,
                    unfreezeDays: input.unfreezeDays,
                  }
                : { workOrderId: input.workOrderId, shareId: input.shareId },
            ),
            input.now,
          ],
        )
      }
      for (const debtOffset of debtOffsets) {
        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, 'after_sales_debt_offset', $2, $3, $4, $5, '验收报酬自动抵扣售后欠款', $6::jsonb, $7)`,
          [
            workerId,
            -debtOffset.amount,
            nextAvailable,
            nextFrozen,
            input.workOrderId,
            JSON.stringify({
              caseId: debtOffset.caseId,
              workOrderId: input.workOrderId,
              shareId: input.shareId,
            }),
            input.now,
          ],
        )
      }
    }

    await client.query(
      `UPDATE work_order_shares SET status = 'accepted', accepted_at = $1, updated_at = $1 WHERE id = $2`,
      [input.now, input.shareId],
    )
    if (workerId > 0) {
      // 先落库份额已验收状态，再按去重后的订单数计算等级进度。
      await maybeUpgradeWorkerLevelWithClient(client, workerId, input.now)
    }
    const progressResult = await client.query<{
      joined_quantity: number
      unfinished_count: number
    }>(
      `SELECT COALESCE(SUM(quantity), 0)::int AS joined_quantity,
              COUNT(*) FILTER (WHERE status != 'accepted' AND status != 'cancelled')::int AS unfinished_count
       FROM work_order_shares WHERE work_order_id = $1 AND status != 'cancelled'`,
      [input.workOrderId],
    )
    const progress = progressResult.rows[0]
    const filled =
      Number(progress?.joined_quantity || 0) >= Number(workOrder.sharing_total_quantity || 1)
    const allAccepted = Number(progress?.unfinished_count || 0) === 0
    const nextOrderStatus = filled && allAccepted ? 'accepted' : workOrder.status
    if (nextOrderStatus === 'accepted') {
      await client.query(
        `UPDATE work_orders SET status = 'accepted', accepted_at = $1, updated_at = $1 WHERE id = $2`,
        [input.now, input.workOrderId],
      )
    }
    await createWorkOrderEventWithClient(client, {
      workOrderId: input.workOrderId,
      actorType: input.actorType || 'admin',
      actorId: input.actorName || '',
      eventType: 'sharing_share_accepted',
      fromStatus: workOrder.status,
      toStatus: nextOrderStatus,
      payloadJson: JSON.stringify({ shareId: input.shareId, workerId }),
      now: input.now,
    })
    const updatedOrder = await getWorkOrderByIdWithClient(client, input.workOrderId)
    const updatedShareResult = await client.query<WorkOrderShareRow>(
      `${WORK_ORDER_SHARE_SELECT} WHERE wos.id = $1 LIMIT 1`,
      [input.shareId],
    )
    return {
      order: updatedOrder,
      share: updatedShareResult.rows[0] || null,
      failureReason: null,
    }
  })
}

/** 后台撤销单个拼单份额，释放该打手押金并把份数重新放回大厅。 */
export async function cancelWorkOrderShare(input: {
  workOrderId: number
  shareId: number
  now: string
  reason?: string
  actorName?: string
}): Promise<{
  order: WorkOrderRow | null
  share: WorkOrderShareRow | null
  releasedDepositAmount: number
  failureReason:
    | 'work_order_not_cancellable'
    | 'share_not_found'
    | 'share_status_not_cancellable'
    | null
}> {
  return withTransaction(async (client) => {
    const orderResult = await client.query<WorkOrderRow>(
      `SELECT * FROM work_orders WHERE id = $1 FOR UPDATE`,
      [input.workOrderId],
    )
    const workOrder = orderResult.rows[0] || null
    if (!workOrder || !['open', 'pending_acceptance', 'in_progress'].includes(workOrder.status)) {
      return {
        order: workOrder,
        share: null,
        releasedDepositAmount: 0,
        failureReason: 'work_order_not_cancellable',
      }
    }

    const shareResult = await client.query<WorkOrderShareRow>(
      `SELECT * FROM work_order_shares WHERE id = $1 AND work_order_id = $2 FOR UPDATE`,
      [input.shareId, input.workOrderId],
    )
    const share = shareResult.rows[0] || null
    if (!share) {
      return {
        order: workOrder,
        share: null,
        releasedDepositAmount: 0,
        failureReason: 'share_not_found',
      }
    }
    const nextOrderStatus = resolveWorkOrderShareCancellationStatus(workOrder.status, share.status)
    if (!nextOrderStatus) {
      return {
        order: workOrder,
        share,
        releasedDepositAmount: 0,
        failureReason: 'share_status_not_cancellable',
      }
    }

    const workerId = Number(share.worker_id || 0)
    let releasedDepositAmount = 0
    if (workerId > 0) {
      await ensureWorkerWalletWithClient(client, workerId, input.now)
      const wallet = await getWorkerWalletWithClient(client, workerId)
      releasedDepositAmount = Math.min(
        Number(share.share_deposit || 0),
        Number(wallet?.frozen_deposit_amount || 0),
      )
      if (releasedDepositAmount > 0) {
        const nextAvailable = Number(wallet?.available_amount || 0) + releasedDepositAmount
        const nextFrozen = Math.max(
          0,
          Number(wallet?.frozen_deposit_amount || 0) - releasedDepositAmount,
        )
        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, 'deposit_release', $2, $3, $4, $5, '后台撤销拼单份额退还押金', $6::jsonb, $7)`,
          [
            workerId,
            releasedDepositAmount,
            nextAvailable,
            nextFrozen,
            input.workOrderId,
            JSON.stringify({
              workOrderId: input.workOrderId,
              shareId: input.shareId,
              reason: String(input.reason || '').trim(),
            }),
            input.now,
          ],
        )
      }
    }

    await client.query(
      `UPDATE work_order_shares
       SET status = 'cancelled', updated_at = $1
       WHERE id = $2`,
      [input.now, input.shareId],
    )
    await client.query(
      `UPDATE work_orders
       SET status = $1,
           submitted_at = NULL,
           published_at = COALESCE(published_at, $2),
           updated_at = $2
       WHERE id = $3`,
      [nextOrderStatus, input.now, input.workOrderId],
    )
    await createWorkOrderEventWithClient(client, {
      workOrderId: input.workOrderId,
      actorType: 'admin',
      actorId: input.actorName || '',
      eventType: 'sharing_share_cancelled_by_admin',
      fromStatus: workOrder.status,
      toStatus: nextOrderStatus,
      payloadJson: JSON.stringify({
        shareId: input.shareId,
        workerId,
        quantity: Number(share.quantity || 0),
        releasedDepositAmount,
        reason: String(input.reason || '').trim(),
      }),
      now: input.now,
    })

    const updatedShareResult = await client.query<WorkOrderShareRow>(
      `${WORK_ORDER_SHARE_SELECT} WHERE wos.id = $1 LIMIT 1`,
      [input.shareId],
    )
    return {
      order: await getWorkOrderByIdWithClient(client, input.workOrderId),
      share: updatedShareResult.rows[0] || null,
      releasedDepositAmount,
      failureReason: null,
    }
  })
}

/**
 * 母单级拼单撤单。只撤回尚未验收的 joined/submitted 份额；已验收份额保留，
 * 取消整单时则要求不存在已验收份额，避免绕过售后和已结算资金处理。
 */
export async function cancelWorkOrderSharing(input: {
  workOrderId: number
  action: 'return_to_hall' | 'cancel_order'
  now: string
  reason?: string
  actorName?: string
}): Promise<{
  order: WorkOrderRow | null
  cancelledShareIds: number[]
  cancelledWorkerIds: number[]
  cancelledShareCount: number
  releasedDepositAmount: number
  failureReason:
    | 'work_order_not_cancellable'
    | 'no_cancellable_shares'
    | 'accepted_shares_present'
    | null
}> {
  return withTransaction(async (client) => {
    const orderResult = await client.query<WorkOrderRow>(
      `SELECT * FROM work_orders WHERE id = $1 FOR UPDATE`,
      [input.workOrderId],
    )
    const workOrder = orderResult.rows[0] || null
    if (!workOrder || workOrder.sharing_enabled !== true) {
      return {
        order: workOrder,
        cancelledShareIds: [],
        cancelledWorkerIds: [],
        cancelledShareCount: 0,
        releasedDepositAmount: 0,
        failureReason: 'work_order_not_cancellable',
      }
    }
    const sharesResult = await client.query<WorkOrderShareRow>(
      `SELECT * FROM work_order_shares
       WHERE work_order_id = $1 AND status != 'cancelled'
       ORDER BY id ASC
       FOR UPDATE`,
      [input.workOrderId],
    )
    const shares = sharesResult.rows
    const plan = resolveWorkOrderSharingCancellationPlan(
      workOrder.status,
      shares.map((share) => share.status),
      input.action,
    )
    if (!plan.nextOrderStatus) {
      return {
        order: workOrder,
        cancelledShareIds: [],
        cancelledWorkerIds: [],
        cancelledShareCount: plan.cancellableShareCount,
        releasedDepositAmount: 0,
        failureReason: plan.failureReason,
      }
    }

    const cancellableShares = shares.filter((share) =>
      ['joined', 'submitted'].includes(share.status),
    )
    let releasedDepositAmount = 0
    for (const share of cancellableShares) {
      const workerId = Number(share.worker_id || 0)
      if (workerId <= 0) continue
      await ensureWorkerWalletWithClient(client, workerId, input.now)
      const wallet = await getWorkerWalletWithClient(client, workerId)
      const releaseAmount = Math.min(
        Number(share.share_deposit || 0),
        Number(wallet?.frozen_deposit_amount || 0),
      )
      if (releaseAmount <= 0) continue
      const nextAvailable = Number(wallet?.available_amount || 0) + releaseAmount
      const nextFrozen = Math.max(0, Number(wallet?.frozen_deposit_amount || 0) - releaseAmount)
      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, 'deposit_release', $2, $3, $4, $5, '后台批量撤销拼单份额退还押金', $6::jsonb, $7)`,
        [
          workerId,
          releaseAmount,
          nextAvailable,
          nextFrozen,
          input.workOrderId,
          JSON.stringify({
            workOrderId: input.workOrderId,
            shareId: Number(share.id),
            action: input.action,
            reason: String(input.reason || '').trim(),
          }),
          input.now,
        ],
      )
      releasedDepositAmount += releaseAmount
    }

    const cancelledShareIds = cancellableShares.map((share) => Number(share.id))
    const cancelledWorkerIds = [
      ...new Set(cancellableShares.map((share) => Number(share.worker_id || 0)).filter(Boolean)),
    ]
    await client.query(
      `UPDATE work_order_shares
       SET status = 'cancelled', updated_at = $1
       WHERE id = ANY($2::bigint[])`,
      [input.now, cancelledShareIds],
    )
    if (input.action === 'return_to_hall') {
      await client.query(
        `UPDATE work_orders
         SET status = 'open', submitted_at = NULL, published_at = COALESCE(published_at, $1),
             hall_queued_at = $1, updated_at = $1
         WHERE id = $2`,
        [input.now, input.workOrderId],
      )
    } else {
      await client.query(
        `UPDATE work_orders
         SET status = 'cancelled', assigned_worker_id = NULL, assigned_at = NULL, deadline_at = NULL,
             submitted_at = NULL, published_at = NULL, pinned_at = NULL, updated_at = $1
         WHERE id = $2`,
        [input.now, input.workOrderId],
      )
    }
    await createWorkOrderEventWithClient(client, {
      workOrderId: input.workOrderId,
      actorType: 'admin',
      actorId: input.actorName || '',
      eventType:
        input.action === 'return_to_hall'
          ? 'sharing_unaccepted_shares_returned_to_hall_by_admin'
          : 'sharing_order_cancelled_by_admin',
      fromStatus: workOrder.status,
      toStatus: plan.nextOrderStatus,
      payloadJson: JSON.stringify({
        cancelledShareIds,
        cancelledShareCount: cancelledShareIds.length,
        acceptedShareCount: plan.acceptedShareCount,
        releasedDepositAmount,
        reason: String(input.reason || '').trim(),
      }),
      now: input.now,
    })
    return {
      order: await getWorkOrderByIdWithClient(client, input.workOrderId),
      cancelledShareIds,
      cancelledWorkerIds,
      cancelledShareCount: cancelledShareIds.length,
      releasedDepositAmount,
      failureReason: null,
    }
  })
}
