import { Injectable, Logger, HttpException, HttpStatus } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { ConfigService } from '@nestjs/config';
import { firstValueFrom } from 'rxjs';
import * as crypto from 'crypto';

@Injectable()
export class PaymobService {
  private readonly logger = new Logger(PaymobService.name);
  private readonly baseUrl = 'https://accept.paymob.com/api';

  constructor(
    private readonly httpService: HttpService,
    private readonly configService: ConfigService,
  ) {}

  /**
   * HMAC Verification for Paymob Webhooks
   */
  verifyHmac(obj: any, hmac: string): boolean {
    const hmacSecret = this.configService.get<string>('paymob.hmacSecret') || '';
    
    // Concatenation order as per Paymob docs
    const data = 
      obj.amount_cents +
      obj.created_at +
      obj.currency +
      obj.error_occured +
      obj.has_parent_transaction +
      obj.id +
      obj.integration_id +
      obj.is_3d_secure +
      obj.is_auth +
      obj.is_capture +
      obj.is_refunded +
      obj.is_standalone_payment +
      obj.source_data.pan +
      obj.source_data.sub_type +
      obj.source_data.type +
      obj.success;

    const calculatedHmac = crypto
      .createHmac('sha512', hmacSecret)
      .update(data)
      .digest('hex');

    return calculatedHmac === hmac;
  }

  /**
   * Step 1: Authentication Request
   * Obtaining an authentication token
   */
  async authenticate(): Promise<string> {
    const apiKey = this.configService.get<string>('paymob.apiKey');
    try {
      const response = await firstValueFrom(
        this.httpService.post(`${this.baseUrl}/auth/tokens`, { api_key: apiKey })
      );
      return response.data.token;
    } catch (error) {
      this.logger.error('Paymob Auth failed', error.response?.data || error.message);
      throw new HttpException('Paymob authentication failed', HttpStatus.BAD_GATEWAY);
    }
  }

  /**
   * Step 2: Order Registration
   */
  async registerOrder(token: string, amountCents: number, currency: string = 'EGP'): Promise<number> {
    try {
      const response = await firstValueFrom(
        this.httpService.post(`${this.baseUrl}/ecommerce/orders`, {
          auth_token: token,
          delivery_needed: false,
          amount_cents: amountCents,
          currency: currency,
          items: [],
        })
      );
      return response.data.id;
    } catch (error) {
      this.logger.error('Paymob Order registration failed', error.response?.data || error.message);
      throw new HttpException('Paymob order registration failed', HttpStatus.BAD_GATEWAY);
    }
  }

  /**
   * Step 3: Payment Key Generation
   */
  async generatePaymentKey(
    token: string,
    orderId: number,
    amountCents: number,
    currency: string = 'EGP',
    billingData: any,
    integrationId: number,
  ): Promise<string> {
    try {
      const response = await firstValueFrom(
        this.httpService.post(`${this.baseUrl}/ecommerce/payment_keys`, {
          auth_token: token,
          amount_cents: amountCents,
          expiration: 3600,
          order_id: orderId,
          billing_data: billingData,
          currency: currency,
          integration_id: integrationId,
        })
      );
      return response.data.token;
    } catch (error) {
      this.logger.error('Paymob Payment Key generation failed', error.response?.data || error.message);
      throw new HttpException('Paymob payment key generation failed', HttpStatus.BAD_GATEWAY);
    }
  }
}
