import { withTransaction } from '../../db/client.js'
import { ensureWorkerWalletWithClient, getWorkerWalletWithClient } from './shared.js'
import type { WorkerDepositUnfreezeRow } from './types.js'
import type { PoolClient } from 'pg'

export function resolveOutstandingDepositAmount(
  totals:
    | {
        frozen_amount?: number
        released_amount?: number
        deducted_amount?: number
      }
    | null
    | undefined,
) {
  return Math.max(
    0,
    Number(totals?.frozen_amount || 0) -
      Number(totals?.released_amount || 0) -
      Number(totals?.deducted_amount || 0),
  )
}

export async function getOutstandingDepositAmountWithClient(
  client: PoolClient,
  workerId: number,
  workOrderId: number,
) {
  const result = await client.query<{
    frozen_amount: number
    released_amount: number
    deducted_amount: number
  }>(
    `
      SELECT
        COALESCE(SUM(CASE WHEN ledger_type = 'deposit_freeze' THEN ABS(amount) ELSE 0 END), 0)::int AS frozen_amount,
        COALESCE(SUM(CASE WHEN ledger_type = 'deposit_release' THEN ABS(amount) ELSE 0 END), 0)::int AS released_amount,
        COALESCE(SUM(CASE WHEN ledger_type = 'deposit_deduction' THEN ABS(amount) ELSE 0 END), 0)::int AS deducted_amount
      FROM worker_wallet_ledgers
      WHERE worker_id = $1 AND related_work_order_id = $2
    `,
    [workerId, workOrderId],
  )
  return resolveOutstandingDepositAmount(result.rows[0])
}

export async function enqueueDepositUnfreezeWithClient(
  client: PoolClient,
  input: {
    workerId: number
    workOrderId: number
    amount: number
    fundType: 'deposit' | 'reward'
    unfreezeDays: number
    now: string
  },
) {
  if (input.amount <= 0) return
  const unfreezeAt = new Date(
    new Date(input.now).getTime() + input.unfreezeDays * 86_400_000,
  ).toISOString()
  await client.query(
    `
      INSERT INTO worker_deposit_unfreezes (
        worker_id, work_order_id, amount, fund_type, unfreeze_at, status, created_at, updated_at
      ) VALUES ($1, $2, $3, $4, $5, 'pending', $6, $6)
    `,
    [input.workerId, input.workOrderId, input.amount, input.fundType, unfreezeAt, input.now],
  )
}

export async function deductPendingDepositUnfreeze(input: {
  workOrderId: number
  amount: number
  note: string
  now: string
}): Promise<{
  deductedAmount: number
  failureReason: 'no_pending_deposit' | 'amount_exceeds_pending' | null
}> {
  return withTransaction(async (client) => {
    const pendingResult = await client.query<WorkerDepositUnfreezeRow>(
      `
        SELECT *
        FROM worker_deposit_unfreezes
        WHERE work_order_id = $1 AND status = 'pending' AND fund_type = 'deposit'
        ORDER BY unfreeze_at ASC
        FOR UPDATE
      `,
      [input.workOrderId],
    )
    const pending = pendingResult.rows
    if (pending.length === 0) {
      return { deductedAmount: 0, failureReason: 'no_pending_deposit' }
    }
    const totalPending = pending.reduce((sum, row) => sum + Number(row.amount || 0), 0)
    if (input.amount <= 0 || input.amount > totalPending) {
      return { deductedAmount: 0, failureReason: 'amount_exceeds_pending' }
    }

    let remainingToDeduct = input.amount
    let deductedAmount = 0

    for (const row of pending) {
      if (remainingToDeduct <= 0) break
      const rowAmount = Number(row.amount || 0)
      if (rowAmount <= 0) continue
      const deductFromRow = Math.min(rowAmount, remainingToDeduct)
      const isFullyDeducted = deductFromRow >= rowAmount

      if (isFullyDeducted) {
        await client.query(
          `
            UPDATE worker_deposit_unfreezes
            SET status = 'deducted', updated_at = $1
            WHERE id = $2
          `,
          [input.now, row.id],
        )
      } else {
        await client.query(
          `
            UPDATE worker_deposit_unfreezes
            SET amount = amount - $1, updated_at = $2
            WHERE id = $3
          `,
          [deductFromRow, input.now, row.id],
        )
      }

      const workerWallet = await getWorkerWalletWithClient(client, row.worker_id)
      await client.query(
        `
          UPDATE worker_wallets
          SET pending_unfreeze_amount = GREATEST(0, pending_unfreeze_amount - $1), updated_at = $2
          WHERE worker_id = $3
        `,
        [deductFromRow, input.now, row.worker_id],
      )
      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_deduction', $2, $3, $4, $5, '问题单扣减待解冻押金', $6::jsonb, $7)
        `,
        [
          row.worker_id,
          -deductFromRow,
          Number(workerWallet?.available_amount || 0),
          Number(workerWallet?.frozen_deposit_amount || 0),
          input.workOrderId,
          JSON.stringify({
            workOrderId: input.workOrderId,
            unfreezeId: row.id,
            note: input.note,
          }),
          input.now,
        ],
      )
      deductedAmount += deductFromRow
      remainingToDeduct -= deductFromRow
    }

    return { deductedAmount, failureReason: null }
  })
}

export async function releaseDepositUnfreeze({
  unfreezeId,
  now,
}: {
  unfreezeId: number
  now: string
}): Promise<WorkerDepositUnfreezeRow | null> {
  return withTransaction(async (client) => {
    const currentResult = await client.query<WorkerDepositUnfreezeRow>(
      `
        SELECT *
        FROM worker_deposit_unfreezes
        WHERE id = $1 AND status = 'pending'
        FOR UPDATE
      `,
      [unfreezeId],
    )
    const unfreeze = currentResult.rows[0] || null
    if (!unfreeze) return null

    await ensureWorkerWalletWithClient(client, unfreeze.worker_id, now)
    const wallet = await getWorkerWalletWithClient(client, unfreeze.worker_id)
    const amount = Math.min(
      Number(unfreeze.amount || 0),
      Number(wallet?.pending_unfreeze_amount || 0),
    )

    await client.query(
      `
        UPDATE worker_deposit_unfreezes
        SET status = 'released', released_at = $1, updated_at = $1
        WHERE id = $2
      `,
      [now, unfreeze.id],
    )

    if (amount > 0) {
      const nextAvailable = Number(wallet?.available_amount || 0) + amount
      const nextPending = Math.max(0, Number(wallet?.pending_unfreeze_amount || 0) - amount)
      await client.query(
        `
          UPDATE worker_wallets
          SET available_amount = $1, pending_unfreeze_amount = $2, updated_at = $3
          WHERE worker_id = $4
        `,
        [nextAvailable, nextPending, now, unfreeze.worker_id],
      )
      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)
        `,
        [
          unfreeze.worker_id,
          unfreeze.fund_type === 'reward' ? 'reward_unfreeze' : 'deposit_unfreeze',
          amount,
          nextAvailable,
          Number(wallet?.frozen_deposit_amount || 0),
          unfreeze.work_order_id,
          unfreeze.fund_type === 'reward' ? '报酬已解冻到账' : '押金已解冻到账',
          JSON.stringify({ unfreezeId: unfreeze.id, fundType: unfreeze.fund_type }),
          now,
        ],
      )
    }

    return {
      ...unfreeze,
      status: 'released',
      released_at: now,
      updated_at: now,
    }
  })
}
