import { MercadoPagoConfig, PreApproval, Payment as MPPayment, Preference } from 'mercadopago';
import { env } from '../../config/env.js';
import { createHmac } from 'crypto';

const config = new MercadoPagoConfig({
  accessToken: env.MP_ACCESS_TOKEN || '',
});

const preApprovalClient = new PreApproval(config);
const paymentClient = new MPPayment(config);
const preferenceClient = new Preference(config);

/**
 * Creates a recurring subscription (preapproval) in MercadoPago.
 * Soporta cadencia mensual (cada 1 mes) o anual (cada 12 meses).
 */
export async function createPreapproval(params: {
  tenantId: string;
  reason: string;
  amount: number;
  payerEmail: string;
  frequency?: 'monthly' | 'annual';
  /**
   * Fecha del primer cobro. Si no se especifica, MP cobra al día siguiente.
   * Útil para reactivaciones: el cliente ya pagó hasta `currentPeriodEnd`,
   * queremos que MP empiece a cobrar desde ese momento, no mañana.
   */
  startDate?: Date;
  /**
   * Referencia externa para el preapproval. Si no se especifica, se usa tenantId.
   * Usar `addon:{subscriptionAddonId}` para preapprovals de addons.
   */
  externalReference?: string;
}) {
  if (!env.MP_ACCESS_TOKEN) {
    throw new Error(
      'MercadoPago no está configurado (falta MP_ACCESS_TOKEN en .env). ' +
      'Pide al dueño de la cuenta que agregue el token de acceso para habilitar cobros.'
    );
  }

  const freq = params.frequency === 'annual'
    ? { frequency: 12, frequency_type: 'months' as const }
    : { frequency: 1,  frequency_type: 'months' as const };

  // start_date sólo se envía si es en el futuro (MP rechaza fechas pasadas).
  const now = new Date();
  const startDateIso = params.startDate && params.startDate.getTime() > now.getTime()
    ? params.startDate.toISOString()
    : undefined;

  const response = await preApprovalClient.create({
    body: {
      reason: params.reason,
      external_reference: params.externalReference || params.tenantId,
      payer_email: params.payerEmail,
      auto_recurring: {
        ...freq,
        transaction_amount: params.amount,
        currency_id: 'MXN',
        ...(startDateIso ? { start_date: startDateIso } : {}),
      },
      back_url: `${env.FRONTEND_URL}/configuracion/suscripcion`,
    },
  });

  return {
    preapprovalId: response.id!,
    initPoint: response.init_point!,
    status: response.status!,
  };
}

/**
 * Cancela un preapproval en MercadoPago. No falla si ya está cancelado o no existe.
 */
export async function cancelPreapproval(preapprovalId: string): Promise<void> {
  try {
    await preApprovalClient.update({
      id: preapprovalId,
      body: { status: 'cancelled' },
    });
  } catch (error: any) {
    // No tiramos el error si el preapproval ya no existe o ya está cancelado
    console.warn(`[MP] cancelPreapproval(${preapprovalId}):`, error.message || error);
  }
}

/**
 * Actualiza el monto recurrente de un preapproval existente (usado en upgrades:
 * después de cobrar el prorateo vía Preference, subimos el monto del preapproval
 * para que el próximo cobro recurrente sea el del plan nuevo).
 */
export async function updatePreapprovalAmount(
  preapprovalId: string,
  newAmount: number,
): Promise<void> {
  if (!env.MP_ACCESS_TOKEN) {
    throw new Error('MercadoPago no está configurado (falta MP_ACCESS_TOKEN)');
  }
  await preApprovalClient.update({
    id: preapprovalId,
    body: {
      auto_recurring: {
        transaction_amount: newAmount,
        currency_id: 'MXN',
      },
    },
  });
}

/**
 * Crea una Preference (checkout de pago único) para cobrar el prorateo de un upgrade.
 * `externalReference` se prefija con `proration:` para que el webhook distinga este
 * pago del cobro recurrente del preapproval.
 */
export async function createProrationPreference(params: {
  tenantId: string;
  subscriptionId: string;
  amount: number;
  description: string;
  payerEmail: string;
}): Promise<{ preferenceId: string; checkoutUrl: string }> {
  if (!env.MP_ACCESS_TOKEN) {
    throw new Error(
      'MercadoPago no está configurado (falta MP_ACCESS_TOKEN en .env). ' +
      'No es posible cobrar el prorateo del upgrade.'
    );
  }

  const response = await preferenceClient.create({
    body: {
      items: [
        {
          id: `proration-${params.subscriptionId}`,
          title: params.description,
          quantity: 1,
          unit_price: params.amount,
          currency_id: 'MXN',
        },
      ],
      payer: { email: params.payerEmail },
      // El prefijo proration: es el marcador que el webhook usa para ramificar
      external_reference: `proration:${params.tenantId}:${params.subscriptionId}`,
      back_urls: {
        success: `${env.FRONTEND_URL}/configuracion/suscripcion?upgrade=success`,
        failure: `${env.FRONTEND_URL}/configuracion/suscripcion?upgrade=failure`,
        pending: `${env.FRONTEND_URL}/configuracion/suscripcion?upgrade=pending`,
      },
      auto_return: 'approved',
    },
  });

  return {
    preferenceId: response.id!,
    checkoutUrl: response.init_point!,
  };
}

/**
 * Crea una Preference (checkout de pago único) para comprar un paquete de
 * timbres adicionales. external_reference = `timbres-pack:${paymentId}` para
 * que el webhook ramifique al handler correspondiente (crea TimbrePaquete +
 * marca Payment approved + emite factura).
 */
export async function createTimbrePackPreference(params: {
  paymentId: string;  // Payment.id del record pre-creado con status=pending
  tenantId: string;
  cantidad: number;
  amount: number;
  payerEmail: string;
}): Promise<{ preferenceId: string; checkoutUrl: string }> {
  if (!env.MP_ACCESS_TOKEN) {
    throw new Error('MercadoPago no está configurado (MP_ACCESS_TOKEN faltante).');
  }

  const title = `${params.cantidad.toLocaleString('es-MX')} timbres adicionales — Horux 360`;

  const response = await preferenceClient.create({
    body: {
      items: [
        {
          id: `timbres-pack-${params.paymentId}`,
          title,
          quantity: 1,
          unit_price: params.amount,
          currency_id: 'MXN',
        },
      ],
      payer: { email: params.payerEmail },
      external_reference: `timbres-pack:${params.paymentId}`,
      back_urls: {
        success: `${env.FRONTEND_URL}/facturacion?timbres=success`,
        failure: `${env.FRONTEND_URL}/facturacion?timbres=failure`,
        pending: `${env.FRONTEND_URL}/facturacion?timbres=pending`,
      },
      auto_return: 'approved',
    },
  });

  return {
    preferenceId: response.id!,
    checkoutUrl: response.init_point!,
  };
}

/**
 * Gets subscription (preapproval) status from MercadoPago
 */
export async function getPreapproval(preapprovalId: string) {
  const response = await preApprovalClient.get({ id: preapprovalId });
  return {
    id: response.id,
    status: response.status,
    payerEmail: response.payer_email,
    nextPaymentDate: response.next_payment_date,
    autoRecurring: response.auto_recurring,
  };
}

/**
 * Gets payment details from MercadoPago
 */
export async function getPaymentDetails(paymentId: string) {
  const response = await paymentClient.get({ id: paymentId });
  return {
    id: response.id,
    status: response.status,
    statusDetail: response.status_detail,
    transactionAmount: response.transaction_amount,
    currencyId: response.currency_id,
    payerEmail: response.payer?.email,
    dateApproved: response.date_approved,
    paymentMethodId: response.payment_method_id,
    externalReference: response.external_reference,
  };
}

/**
 * Verifies MercadoPago webhook signature (HMAC-SHA256)
 */
export function verifyWebhookSignature(
  xSignature: string,
  xRequestId: string,
  dataId: string
): boolean {
  if (!env.MP_WEBHOOK_SECRET) {
    console.error('[WEBHOOK] MP_WEBHOOK_SECRET not configured - rejecting webhook');
    return false;
  }

  // Parse x-signature header: "ts=...,v1=..."
  const parts: Record<string, string> = {};
  for (const part of xSignature.split(',')) {
    const [key, value] = part.split('=');
    parts[key.trim()] = value.trim();
  }

  const ts = parts['ts'];
  const v1 = parts['v1'];
  if (!ts || !v1) return false;

  // Build the manifest string
  const manifest = `id:${dataId};request-id:${xRequestId};ts:${ts};`;
  const hmac = createHmac('sha256', env.MP_WEBHOOK_SECRET)
    .update(manifest)
    .digest('hex');

  return hmac === v1;
}
