/**
 * Payment Webhook Handlers
 * Handle webhooks from PayPal, Square, Chime, and other payment providers
 */

import { Router } from 'express';

export interface WebhookEvent {
  id: string;
  type: string;
  timestamp: Date;
  data: Record<string, any>;
  verified: boolean;
}

export interface PaymentWebhookResult {
  success: boolean;
  transactionId?: string;
  status?: string;
  coinsAdded?: number;
  error?: string;
}

/**
 * Square Webhook Handler
 */
export async function handleSquareWebhook(
  event: any
): Promise<PaymentWebhookResult> {
  try {
    const { type, data } = event;

    switch (type) {
      case 'payment.created':
      case 'payment.updated':
        return handleSquarePayment(data.object);
      case 'refund.created':
        return handleSquareRefund(data.object);
      default:
        return { success: true };
    }
  } catch (error) {
    console.error('[Square Webhook Error]', error);
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error',
    };
  }
}

async function handleSquarePayment(payment: any): Promise<PaymentWebhookResult> {
  const { id, status, amount_money, customer_id, receipt_url } = payment;

  if (status !== 'COMPLETED') {
    return { success: true, status };
  }

  const amountUSD = amount_money.amount / 100;
  const coinsAdded = Math.floor(amountUSD * 100); // 1 USD = 100 coins

  console.log(
    `[Square] Payment completed: ${id}, Amount: $${amountUSD}, Coins: ${coinsAdded}`
  );

  return {
    success: true,
    transactionId: id,
    status: 'completed',
    coinsAdded,
  };
}

async function handleSquareRefund(refund: any): Promise<PaymentWebhookResult> {
  const { id, payment_id, amount_money, status } = refund;

  console.log(
    `[Square] Refund processed: ${id} for payment ${payment_id}, Status: ${status}`
  );

  return {
    success: true,
    transactionId: payment_id,
    status: 'refunded',
  };
}

/**
 * PayPal Webhook Handler
 */
export async function handlePayPalWebhook(
  event: any
): Promise<PaymentWebhookResult> {
  try {
    const { event_type, resource } = event;

    switch (event_type) {
      case 'PAYMENT.CAPTURE.COMPLETED':
        return handlePayPalCapture(resource);
      case 'PAYMENT.CAPTURE.REFUNDED':
        return handlePayPalRefund(resource);
      case 'PAYMENT.CAPTURE.DENIED':
        return handlePayPalDenied(resource);
      default:
        return { success: true };
    }
  } catch (error) {
    console.error('[PayPal Webhook Error]', error);
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error',
    };
  }
}

async function handlePayPalCapture(
  resource: any
): Promise<PaymentWebhookResult> {
  const { id, status, amount } = resource;

  if (status !== 'COMPLETED') {
    return { success: true, status };
  }

  const amountUSD = parseFloat(amount.value);
  const coinsAdded = Math.floor(amountUSD * 100);

  console.log(
    `[PayPal] Payment captured: ${id}, Amount: $${amountUSD}, Coins: ${coinsAdded}`
  );

  return {
    success: true,
    transactionId: id,
    status: 'completed',
    coinsAdded,
  };
}

async function handlePayPalRefund(
  resource: any
): Promise<PaymentWebhookResult> {
  const { id, links } = resource;

  // Extract original transaction ID from links
  const captureLink = links.find((link: any) => link.rel === 'up');
  const captureId = captureLink?.href.split('/').pop();

  console.log(`[PayPal] Refund processed: ${id} for capture ${captureId}`);

  return {
    success: true,
    transactionId: captureId,
    status: 'refunded',
  };
}

async function handlePayPalDenied(
  resource: any
): Promise<PaymentWebhookResult> {
  const { id, status_details } = resource;

  console.log(
    `[PayPal] Payment denied: ${id}, Reason: ${status_details?.reason}`
  );

  return {
    success: false,
    transactionId: id,
    status: 'denied',
    error: status_details?.reason || 'Payment denied',
  };
}

/**
 * Chime Webhook Handler
 */
export async function handleChimeWebhook(
  event: any
): Promise<PaymentWebhookResult> {
  try {
    const { event_type, data } = event;

    switch (event_type) {
      case 'transfer.completed':
        return handleChimeTransfer(data);
      case 'transfer.failed':
        return handleChimeTransferFailed(data);
      case 'verification.completed':
        return handleChimeVerification(data);
      default:
        return { success: true };
    }
  } catch (error) {
    console.error('[Chime Webhook Error]', error);
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error',
    };
  }
}

async function handleChimeTransfer(data: any): Promise<PaymentWebhookResult> {
  const { transfer_id, amount, status, user_id } = data;

  if (status !== 'completed') {
    return { success: true, status };
  }

  const amountUSD = amount / 100;
  const coinsAdded = Math.floor(amountUSD * 100);

  console.log(
    `[Chime] Transfer completed: ${transfer_id}, Amount: $${amountUSD}, Coins: ${coinsAdded}`
  );

  return {
    success: true,
    transactionId: transfer_id,
    status: 'completed',
    coinsAdded,
  };
}

async function handleChimeTransferFailed(
  data: any
): Promise<PaymentWebhookResult> {
  const { transfer_id, failure_reason } = data;

  console.log(
    `[Chime] Transfer failed: ${transfer_id}, Reason: ${failure_reason}`
  );

  return {
    success: false,
    transactionId: transfer_id,
    status: 'failed',
    error: failure_reason,
  };
}

async function handleChimeVerification(
  data: any
): Promise<PaymentWebhookResult> {
  const { verification_id, status } = data;

  console.log(
    `[Chime] Verification completed: ${verification_id}, Status: ${status}`
  );

  return {
    success: true,
    status: 'verified',
  };
}

/**
 * Google Pay Webhook Handler
 */
export async function handleGooglePayWebhook(
  event: any
): Promise<PaymentWebhookResult> {
  try {
    const { eventType, payload } = event;

    switch (eventType) {
      case 'TRANSACTION_COMPLETED':
        return handleGooglePayTransaction(payload);
      case 'TRANSACTION_FAILED':
        return handleGooglePayFailed(payload);
      default:
        return { success: true };
    }
  } catch (error) {
    console.error('[Google Pay Webhook Error]', error);
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error',
    };
  }
}

async function handleGooglePayTransaction(
  payload: any
): Promise<PaymentWebhookResult> {
  const { transactionId, amount, currency, status } = payload;

  if (status !== 'SUCCESS') {
    return { success: true, status };
  }

  const amountUSD = amount;
  const coinsAdded = Math.floor(amountUSD * 100);

  console.log(
    `[Google Pay] Transaction completed: ${transactionId}, Amount: $${amountUSD}, Coins: ${coinsAdded}`
  );

  return {
    success: true,
    transactionId,
    status: 'completed',
    coinsAdded,
  };
}

async function handleGooglePayFailed(
  payload: any
): Promise<PaymentWebhookResult> {
  const { transactionId, failureReason } = payload;

  console.log(
    `[Google Pay] Transaction failed: ${transactionId}, Reason: ${failureReason}`
  );

  return {
    success: false,
    transactionId,
    status: 'failed',
    error: failureReason,
  };
}

/**
 * Generic webhook processor
 */
export async function processPaymentWebhook(
  provider: string,
  event: any
): Promise<PaymentWebhookResult> {
  console.log(`[Webhook] Processing ${provider} event:`, event.id || event.event_type);

  switch (provider.toLowerCase()) {
    case 'square':
      return handleSquareWebhook(event);
    case 'paypal':
      return handlePayPalWebhook(event);
    case 'chime':
      return handleChimeWebhook(event);
    case 'google_pay':
      return handleGooglePayWebhook(event);
    default:
      return {
        success: false,
        error: `Unknown payment provider: ${provider}`,
      };
  }
}

/**
 * Webhook signature verification
 */
export function verifyWebhookSignature(
  provider: string,
  payload: string,
  signature: string,
  secret: string
): boolean {
  // Implementation depends on provider
  // This is a placeholder - actual implementation would use provider-specific verification

  console.log(`[Webhook] Verifying ${provider} signature`);

  // For now, return true - in production, implement proper verification
  return true;
}

/**
 * Webhook retry logic
 */
export interface WebhookRetryConfig {
  maxRetries: number;
  retryDelayMs: number;
  backoffMultiplier: number;
}

export const DEFAULT_WEBHOOK_RETRY_CONFIG: WebhookRetryConfig = {
  maxRetries: 3,
  retryDelayMs: 1000,
  backoffMultiplier: 2,
};

export async function retryWebhookProcessing(
  processor: () => Promise<PaymentWebhookResult>,
  config: WebhookRetryConfig = DEFAULT_WEBHOOK_RETRY_CONFIG
): Promise<PaymentWebhookResult> {
  let lastError: Error | null = null;
  let delay = config.retryDelayMs;

  for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
    try {
      return await processor();
    } catch (error) {
      lastError = error as Error;
      console.error(
        `[Webhook] Processing failed (attempt ${attempt + 1}/${config.maxRetries + 1}):`,
        lastError.message
      );

      if (attempt < config.maxRetries) {
        await new Promise(resolve => setTimeout(resolve, delay));
        delay *= config.backoffMultiplier;
      }
    }
  }

  return {
    success: false,
    error: lastError?.message || 'Max retries exceeded',
  };
}

/**
 * Webhook event logging
 */
export interface WebhookLog {
  id: string;
  provider: string;
  eventType: string;
  status: 'received' | 'processing' | 'completed' | 'failed';
  result: PaymentWebhookResult;
  timestamp: Date;
  retries: number;
}

export const webhookLogs: WebhookLog[] = [];

export function logWebhookEvent(
  provider: string,
  eventType: string,
  result: PaymentWebhookResult,
  retries: number = 0
): void {
  const log: WebhookLog = {
    id: `webhook-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
    provider,
    eventType,
    status: result.success ? 'completed' : 'failed',
    result,
    timestamp: new Date(),
    retries,
  };

  webhookLogs.push(log);

  // Keep only last 1000 logs in memory
  if (webhookLogs.length > 1000) {
    webhookLogs.shift();
  }

  console.log(`[Webhook Log] ${provider} - ${eventType} - ${log.status}`);
}

/**
 * Get webhook logs
 */
export function getWebhookLogs(
  provider?: string,
  limit: number = 100
): WebhookLog[] {
  let logs = webhookLogs;

  if (provider) {
    logs = logs.filter(log => log.provider === provider);
  }

  return logs.slice(-limit);
}
