import * as crypto from 'crypto';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { type PaymentProvider } from '@prisma/client';
import { LoggerService } from '@modules/shared';
import {
  type IPaymentGateway,
  type CreatePaymentUrlParams,
  type CreatePaymentUrlResult,
  type CallbackVerifyResult,
  type RefundParams,
  type RefundResult,
} from './payment-gateway.interface';

/**
 * Bank transfer payment gateway.
 *
 * Unlike VNPay/MoMo/ZaloPay, bank transfers have no external redirect.
 * `createPaymentUrl` returns a reference page URL with transfer instructions
 * (bank name, account number, amount, transfer content).
 * Confirmation is manual — an admin calls the confirm-transfer endpoint
 * which triggers `verifyCallback` with admin-signed data.
 */
@Injectable()
export class BankTransferService implements IPaymentGateway {
  readonly provider: PaymentProvider = 'BANK_TRANSFER';

  private readonly bankAccountNumber: string;
  private readonly bankName: string;
  private readonly accountHolder: string;
  private readonly webhookSecret: string;
  private readonly instructionsBaseUrl: string;

  constructor(
    private readonly config: ConfigService,
    private readonly logger: LoggerService,
  ) {
    this.bankAccountNumber = this.config.getOrThrow<string>('BANK_TRANSFER_ACCOUNT_NUMBER');
    this.bankName = this.config.getOrThrow<string>('BANK_TRANSFER_BANK_NAME');
    this.accountHolder = this.config.getOrThrow<string>('BANK_TRANSFER_ACCOUNT_HOLDER');
    this.webhookSecret = this.config.getOrThrow<string>('BANK_TRANSFER_WEBHOOK_SECRET');
    this.instructionsBaseUrl = this.config.get<string>(
      'BANK_TRANSFER_INSTRUCTIONS_URL',
      'https://goodgo.vn/thanh-toan/chuyen-khoan',
    );
  }

  async createPaymentUrl(params: CreatePaymentUrlParams): Promise<CreatePaymentUrlResult> {
    const transferContent = `GG ${params.orderId}`;
    const providerTxId = `BT-${params.orderId}`;

    const queryParams = new URLSearchParams({
      ref: providerTxId,
      amount: params.amountVND.toString(),
      bank: this.bankName,
      account: this.bankAccountNumber,
      holder: this.accountHolder,
      content: transferContent,
    });

    const paymentUrl = `${this.instructionsBaseUrl}?${queryParams.toString()}`;

    this.logger.log(
      `Bank transfer instructions created for order ${params.orderId}: bank=${this.bankName}, amount=${params.amountVND}`,
      'BankTransferService',
    );

    return { paymentUrl, providerTxId };
  }

  verifyCallback(data: Record<string, string>): CallbackVerifyResult {
    const signature = data['signature'] ?? '';
    const orderId = data['orderId'] ?? '';
    const providerTxId = data['providerTxId'] ?? '';
    const status = data['status'] ?? '';
    const confirmedBy = data['confirmedBy'] ?? '';

    // Build canonical string for HMAC verification
    const canonicalString = [orderId, providerTxId, status, confirmedBy].join('|');
    const hmac = crypto.createHmac('sha256', this.webhookSecret);
    const expectedSignature = hmac.update(Buffer.from(canonicalString, 'utf-8')).digest('hex');

    let isValid = false;
    try {
      isValid =
        signature.length === expectedSignature.length &&
        crypto.timingSafeEqual(
          Buffer.from(signature, 'hex'),
          Buffer.from(expectedSignature, 'hex'),
        );
    } catch {
      isValid = false;
    }

    const isSuccess = isValid && status === 'CONFIRMED';

    this.logger.log(
      `Bank transfer callback verified: orderId=${orderId}, valid=${isValid}, success=${isSuccess}`,
      'BankTransferService',
    );

    return {
      isValid,
      orderId,
      providerTxId,
      isSuccess,
      rawData: data,
    };
  }

  async refund(params: RefundParams): Promise<RefundResult> {
    // Bank transfer refunds require manual processing — not automatable
    this.logger.warn(
      `Bank transfer refund requires manual processing: providerTxId=${params.providerTxId}, amount=${params.amountVND}, reason=${params.reason}`,
      'BankTransferService',
    );

    return { success: false, refundTxId: null };
  }

  /**
   * Generate an HMAC-SHA256 signature for admin confirmation data.
   * Used internally by the confirm-transfer command handler.
   */
  generateConfirmationSignature(
    orderId: string,
    providerTxId: string,
    status: string,
    confirmedBy: string,
  ): string {
    const canonicalString = [orderId, providerTxId, status, confirmedBy].join('|');
    const hmac = crypto.createHmac('sha256', this.webhookSecret);
    return hmac.update(Buffer.from(canonicalString, 'utf-8')).digest('hex');
  }

  /** Return bank transfer display info for a payment. */
  getBankTransferInfo(): {
    bankName: string;
    accountNumber: string;
    accountHolder: string;
  } {
    return {
      bankName: this.bankName,
      accountNumber: this.bankAccountNumber,
      accountHolder: this.accountHolder,
    };
  }
}
