import crypto from "crypto";

export interface RedsysConfig {
  merchantCode: string;
  terminal: string;
  secretKey: string; // Clave secreta SHA-256 proporcionada por el banco
  environment: "test" | "production";
}

export const DEFAULT_REDSYS_CONFIG: RedsysConfig = {
  merchantCode: "999008881", // Código TPV pruebas estándar
  terminal: "1",
  secretKey: "sq7HjrUqGRvcNmRj7RrWhRPoqJN6WNyjp", // Clave de prueba Redsys
  environment: "test",
};

export const REDSYS_URLS = {
  test: "https://sis-t.redsys.es:25443/sis/realizarPago",
  production: "https://sis.redsys.es/sis/realizarPago",
};

/**
 * Diversifica la clave del comercio con el número de pedido usando 3DES (Triple DES CBC)
 */
function encrypt3DES(order: string, keyBase64: string): Buffer {
  const key = Buffer.from(keyBase64, "base64");
  const iv = Buffer.alloc(8, 0); // IV de 8 bytes ceros
  const cipher = crypto.createCipheriv("des-ede3-cbc", key, iv);
  cipher.setAutoPadding(true);
  
  // Padding manual a 8 bytes si es necesario
  let orderPadded = Buffer.from(order, "utf8");
  const padLength = 8 - (orderPadded.length % 8);
  if (padLength < 8) {
    const pad = Buffer.alloc(padLength, 0);
    orderPadded = Buffer.concat([orderPadded, pad]);
  }
  
  const encrypted = Buffer.concat([cipher.update(orderPadded), cipher.final()]);
  return encrypted.subarray(0, 16); // Usar los primeros 16 bytes
}

/**
 * Calcula la firma HMAC SHA-256 para los parámetros de Redsys
 */
function calculateHmacSha256(merchantParametersBase64: string, derivedKey: Buffer): string {
  const hmac = crypto.createHmac("sha256", derivedKey);
  hmac.update(merchantParametersBase64, "utf8");
  return hmac.digest("base64");
}

export interface RedsysPaymentParams {
  orderNumber: string;
  amount: number; // en euros, ej 32.50
  productDescription: string;
  customerName?: string;
  isBizum?: boolean;
  urlOk: string;
  urlKo: string;
  merchantUrl?: string;
}

export function createRedsysPaymentForm(
  params: RedsysPaymentParams,
  config: RedsysConfig = DEFAULT_REDSYS_CONFIG
) {
  // Convertir importe a céntimos enteros (32.50€ -> 3250)
  const amountInCents = Math.round(params.amount * 100).toString();

  // El formato del pedido Redsys debe ser de 4 a 12 caracteres alfanuméricos
  // (primeros 4 dígitos obligatorios)
  const redsysOrder = params.orderNumber.replace(/[^0-9a-zA-Z]/g, "").slice(0, 12).padStart(4, "0");

  const merchantParamsObj: Record<string, string> = {
    DS_MERCHANT_AMOUNT: amountInCents,
    DS_MERCHANT_ORDER: redsysOrder,
    DS_MERCHANT_MERCHANTCODE: config.merchantCode,
    DS_MERCHANT_CURRENCY: "978", // EUR
    DS_MERCHANT_TRANSACTIONTYPE: "0", // Autorización
    DS_MERCHANT_TERMINAL: config.terminal,
    DS_MERCHANT_MERCHANTNAME: "RAUL ASENCIO PASTELERIAS",
    DS_MERCHANT_PRODUCTDESCRIPTION: params.productDescription.slice(0, 125),
    DS_MERCHANT_URLOK: params.urlOk,
    DS_MERCHANT_URLKO: params.urlKo,
  };

  if (params.merchantUrl) {
    merchantParamsObj.DS_MERCHANT_MERCHANTURL = params.merchantUrl;
  }

  if (params.isBizum) {
    merchantParamsObj.DS_MERCHANT_PAYMETHODS = "z"; // 'z' indica método Bizum en Redsys
  }

  const jsonString = JSON.stringify(merchantParamsObj);
  const merchantParametersBase64 = Buffer.from(jsonString, "utf8").toString("base64");

  // Calcular firma
  const derivedKey = encrypt3DES(redsysOrder, config.secretKey);
  const signature = calculateHmacSha256(merchantParametersBase64, derivedKey);

  return {
    actionUrl: REDSYS_URLS[config.environment],
    Ds_SignatureVersion: "HMAC_SHA256_V1",
    Ds_MerchantParameters: merchantParametersBase64,
    Ds_Signature: signature,
    redsysOrder,
    amountInCents,
  };
}
