import { and, eq, sql } from 'drizzle-orm'
import type { TransactionalDatabase } from '@platform-modules/db'
import { OrderNotChargeableError, OrderValidationError } from '../errors.js'
import { order, refundIntent, type OrdersSchema } from '../schema.js'
import { settleRefundIntentInTx } from './execute-refund.js'
import type { RefundPort } from './types.js'

const DEFAULT_LIMIT = 100

export type RefundSweepFailure = {
  intentId: string
  orderId: string
  error: unknown
}

export type RefundSweepResult = {
  scanned: number
  settled: number
  stillPending: number
  failures: RefundSweepFailure[]
}

export async function reconcileStuckRefunds(
  db: TransactionalDatabase<OrdersSchema>,
  refund: RefundPort,
  opts?: { olderThan?: Date; limit?: number },
): Promise<RefundSweepResult> {
  const limit = opts?.limit ?? DEFAULT_LIMIT

  const conditions = [eq(refundIntent.status, 'pending')]
  if (opts?.olderThan !== undefined) {
    conditions.push(sql`${refundIntent.createdAt} < ${opts.olderThan}`)
  }

  // Headless core: never write to console for unknown adopters. A caller that
  // passes `limit` paginates by re-sweeping while `scanned === limit` — the
  // backlog signal is in the return shape, not a stdout log.
  const pendingIntents = await db
    .select()
    .from(refundIntent)
    .where(and(...conditions))
    .orderBy(refundIntent.createdAt)
    .limit(limit)

  let settled = 0
  let stillPending = 0
  const failures: RefundSweepFailure[] = []

  for (const intent of pendingIntents) {
    try {
      const [orderRow] = await db
        .select({ chargeRef: order.chargeRef })
        .from(order)
        .where(eq(order.id, intent.orderId))

      if (!orderRow?.chargeRef) {
        failures.push({
          intentId: intent.id,
          orderId: intent.orderId,
          error: new OrderNotChargeableError(intent.orderId),
        })
        continue
      }

      if (intent.amount > BigInt(Number.MAX_SAFE_INTEGER)) {
        failures.push({
          intentId: intent.id,
          orderId: intent.orderId,
          error: new OrderValidationError('amount'),
        })
        continue
      }

      const res = await refund({
        refundKey: intent.refundKey,
        chargeKey: orderRow.chargeRef,
        refundId: intent.id,
        amount: Number(intent.amount),
      })

      if (res.kind === 'pending') {
        stillPending++
        continue
      }

      const didSettle = await db.transaction((tx) =>
        settleRefundIntentInTx(tx, intent.id, intent.orderId, res.providerRef),
      )

      if (didSettle) {
        settled++
      }
    } catch (error) {
      failures.push({ intentId: intent.id, orderId: intent.orderId, error })
    }
  }

  return { scanned: pendingIntents.length, settled, stillPending, failures }
}
