import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import {
  PaymentProviderPort,
  PaymentProviderType,
  CreatePaymentParams,
  PaymentSession,
  PaymentResult,
  WebhookResult,
} from '../../../domain/ports/payment-provider.port';
import { InvoiceCurrency } from '../../../domain/entities/invoice.entity';

@Injectable()
export class AlipayProvider implements PaymentProviderPort {
  readonly providerType = PaymentProviderType.ALIPAY;
  private readonly logger = new Logger(AlipayProvider.name);
  private appId: string;
  private privateKey: string;
  private configured = false;

  constructor(private readonly configService: ConfigService) {
    this.appId = this.configService.get<string>('ALIPAY_APP_ID', '');
    this.privateKey = this.configService.get<string>('ALIPAY_PRIVATE_KEY', '');
    this.configured = !!(this.appId && this.privateKey);
  }

  isConfigured(): boolean {
    return this.configured;
  }

  async createPaymentSession(params: CreatePaymentParams): Promise<PaymentSession> {
    if (!this.configured) throw new Error('Alipay not configured');

    // For CNY: use amount directly; for USD: this should not happen but handle gracefully
    if (params.currency !== InvoiceCurrency.CNY) {
      throw new Error('Alipay only supports CNY payments');
    }

    // Dynamic import to avoid load errors when alipay-sdk is not installed
    const AlipaySdkModule = await import('alipay-sdk');
    const AlipaySdk = AlipaySdkModule.default ?? AlipaySdkModule;
    const client = new (AlipaySdk as any)({
      appId: this.appId,
      privateKey: this.privateKey,
      signType: 'RSA2',
      gateway: 'https://openapi.alipay.com/gateway.do',
    });

    // alipay amount is in yuan (CNY fen / 100)
    const amountYuan = (params.amount / 100).toFixed(2);
    const outTradeNo = `it0-${params.invoiceId}-${Date.now()}`;

    // PC scan QR code payment
    const result = await client.exec('alipay.trade.precreate', {
      bizContent: {
        out_trade_no: outTradeNo,
        total_amount: amountYuan,
        subject: params.description,
      },
    });

    return {
      providerPaymentId: outTradeNo,
      qrCodeUrl: result.qrCode,
      expiresAt: new Date(Date.now() + 2 * 60 * 60 * 1000), // 2 hours
    };
  }

  async confirmPayment(providerPaymentId: string): Promise<PaymentResult> {
    // Alipay uses async webhook notification; sync confirm not needed
    return { providerPaymentId, status: 'pending', amount: 0, currency: 'CNY' };
  }

  async handleWebhook(rawBody: Buffer, _headers: Record<string, string>): Promise<WebhookResult> {
    if (!this.configured) throw new Error('Alipay not configured');

    // Parse URL-encoded body
    const params = new URLSearchParams(rawBody.toString());
    const notifyData: Record<string, string> = {};
    params.forEach((v, k) => { notifyData[k] = v; });

    // Verify Alipay signature using alipay-sdk
    const AlipaySdkModule = await import('alipay-sdk');
    const AlipaySdk = AlipaySdkModule.default ?? AlipaySdkModule;
    const client = new (AlipaySdk as any)({
      appId: this.appId,
      privateKey: this.privateKey,
      signType: 'RSA2',
      gateway: 'https://openapi.alipay.com/gateway.do',
    });

    const isValid = client.checkNotifySign(notifyData);
    if (!isValid) throw new Error('Alipay webhook signature invalid');

    const tradeStatus = notifyData['trade_status'];
    const outTradeNo = notifyData['out_trade_no'];

    if (tradeStatus === 'TRADE_SUCCESS' || tradeStatus === 'TRADE_FINISHED') {
      return { type: 'payment_succeeded', providerPaymentId: outTradeNo };
    } else if (tradeStatus === 'TRADE_CLOSED') {
      return { type: 'payment_failed', providerPaymentId: outTradeNo };
    }

    return { type: 'unknown' };
  }
}
