import { getDb } from '../db/client.js'
import { PairingFailureCause, PairingFailureOperatorAction } from '../constants.js'

const sql = getDb()

/**
 * Insert a pairing_failures row. Called from payment.service.failPaymentSession (and the
 * background sweeper for `payment_request_expired`).
 */
export const recordFailure = async ({ paymentRequestId, customerId, targetedMitraId = null, causeTag, amount }) => {
  if (!Object.values(PairingFailureCause).includes(causeTag)) {
    throw Object.assign(new Error(`Unknown cause_tag: ${causeTag}`), { code: 'VALIDATION_ERROR', statusCode: 422 })
  }
  const [row] = await sql`
    INSERT INTO pairing_failures (
      payment_request_id, customer_id, targeted_mitra_id, cause_tag, amount
    )
    VALUES (
      ${paymentRequestId}, ${customerId}, ${targetedMitraId}, ${causeTag}, ${amount}
    )
    RETURNING id, payment_request_id, customer_id, targeted_mitra_id, cause_tag, amount,
              operator_action, actioned_by, actioned_at, created_at
  `
  return row
}

/**
 * Control-center listing with optional filters. Returns rows + total count.
 */
export const listFailures = async ({ causeTags = null, dateFrom = null, dateTo = null, limit = 50, offset = 0 } = {}) => {
  const safeLimit = Math.min(Math.max(Number(limit) || 50, 1), 200)
  const safeOffset = Math.max(Number(offset) || 0, 0)

  const items = await sql`
    SELECT
      pf.id, pf.payment_request_id, pf.customer_id, pf.targeted_mitra_id,
      pf.cause_tag, pf.amount, pf.operator_action, pf.actioned_by, pf.actioned_at, pf.created_at,
      c.display_name AS customer_call_name,
      m.display_name AS targeted_mitra_call_name,
      cc.display_name AS actioned_by_name
    FROM pairing_failures pf
    JOIN customers c ON c.id = pf.customer_id
    LEFT JOIN mitras m ON m.id = pf.targeted_mitra_id
    LEFT JOIN control_center_users cc ON cc.id = pf.actioned_by
    WHERE
      ${causeTags && causeTags.length > 0 ? sql`pf.cause_tag IN ${sql(causeTags)}` : sql`TRUE`}
      AND ${dateFrom ? sql`pf.created_at >= ${dateFrom}` : sql`TRUE`}
      AND ${dateTo ? sql`pf.created_at <= ${dateTo}` : sql`TRUE`}
    ORDER BY pf.created_at DESC
    LIMIT ${safeLimit} OFFSET ${safeOffset}
  `

  const [{ count }] = await sql`
    SELECT COUNT(*) FROM pairing_failures pf
    WHERE
      ${causeTags && causeTags.length > 0 ? sql`pf.cause_tag IN ${sql(causeTags)}` : sql`TRUE`}
      AND ${dateFrom ? sql`pf.created_at >= ${dateFrom}` : sql`TRUE`}
      AND ${dateTo ? sql`pf.created_at <= ${dateTo}` : sql`TRUE`}
  `

  return { rows: items, total: Number(count), limit: safeLimit, offset: safeOffset }
}

/**
 * Operator action menu — record the chosen action against a failure row.
 * Each call overwrites the previous decision (operator can change their mind).
 */
export const setOperatorAction = async (failureId, ccUserId, action) => {
  if (!Object.values(PairingFailureOperatorAction).includes(action)) {
    throw Object.assign(new Error(`Unknown operator action: ${action}`), { code: 'VALIDATION_ERROR', statusCode: 422 })
  }
  const [updated] = await sql`
    UPDATE pairing_failures
    SET operator_action = ${action},
        actioned_by = ${ccUserId},
        actioned_at = NOW()
    WHERE id = ${failureId}
    RETURNING id, payment_request_id, customer_id, targeted_mitra_id, cause_tag, amount,
              operator_action, actioned_by, actioned_at, created_at
  `
  if (!updated) {
    throw Object.assign(new Error('Failure row not found'), { code: 'NOT_FOUND', statusCode: 404 })
  }
  return updated
}
