import { spendDPoints, creditDPoints, spendVPoints, creditVPoints, PD_PER_UNIT } from './dpoints'

/**
 * Los PV (vote points) son gratis (se ganan votando), así que pagar con PV es
 * más caro que con PD: cuesta este factor por el coste en PD. Cambiar aquí.
 */
export const VP_PRICE_FACTOR = 2

/** Coste en PD de un precio en euros (100 PD = 1 €). */
export function dpointsCost(priceEur: number): number {
  return Math.round(priceEur * PD_PER_UNIT)
}

/** Coste en PV de un precio en euros (coste PD × VP_PRICE_FACTOR). */
export function vpointsCost(priceEur: number): number {
  return dpointsCost(priceEur) * VP_PRICE_FACTOR
}

/**
 * Paga un servicio con el saldo PD: descuenta el coste de forma atómica y
 * ejecuta la acción al momento (sin pasarela). Si la ejecución falla, reembolsa
 * el saldo. Devuelve `insufficientPd` si no hay saldo suficiente.
 */
export async function payServiceWithDPoints(
  accountId: number,
  priceEur: number,
  fulfill: () => Promise<boolean>,
): Promise<{ success: boolean; error?: string }> {
  const cost = dpointsCost(priceEur)
  if (!(cost > 0)) return { success: false, error: 'invalidRequest' }
  const spent = await spendDPoints(accountId, cost)
  if (!spent.success) {
    return { success: false, error: spent.error === 'insufficientFunds' ? 'insufficientPd' : 'genericError' }
  }
  let ok = false
  try {
    ok = await fulfill()
  } catch {
    ok = false
  }
  if (!ok) {
    await creditDPoints(accountId, cost) // reembolso si no se pudo ejecutar
    return { success: false, error: 'fulfillFailed' }
  }
  return { success: true }
}

/**
 * Paga un servicio con el saldo PV: descuenta el coste (más caro que en PD) y
 * ejecuta la acción al momento. Reembolsa si falla. Devuelve `insufficientVp`
 * si no hay saldo suficiente.
 */
export async function payServiceWithVPoints(
  accountId: number,
  priceEur: number,
  fulfill: () => Promise<boolean>,
): Promise<{ success: boolean; error?: string }> {
  const cost = vpointsCost(priceEur)
  if (!(cost > 0)) return { success: false, error: 'invalidRequest' }
  const spent = await spendVPoints(accountId, cost)
  if (!spent.success) {
    return { success: false, error: spent.error === 'insufficientFunds' ? 'insufficientVp' : 'genericError' }
  }
  let ok = false
  try {
    ok = await fulfill()
  } catch {
    ok = false
  }
  if (!ok) {
    await creditVPoints(accountId, cost) // reembolso si no se pudo ejecutar
    return { success: false, error: 'fulfillFailed' }
  }
  return { success: true }
}
