import { PaymentGateway, PaymentLinkResult, PaymentVerificationResult, SeamlessPaymentResult } from '../interfaces/payment-gateway.interface';
import { MockGateway } from './mock.gateway';
import axios from 'axios';
import * as crypto from 'crypto';


export class PaynowGateway implements PaymentGateway {
  private readonly integrationId: string;
  private readonly integrationKey: string;
  private readonly isSandbox: boolean;

  constructor(credentials: Record<string, any>) {
    this.integrationId = credentials.paynowIntegrationId || '';
    this.integrationKey = credentials.paynowIntegrationKey || '';
    this.isSandbox = credentials.isSandbox ?? false;
  }

  private generateHash(values: Record<string, string>): string {
    // 1. Sort the key/value pairs by key name in alphabetical order
    const sortedKeys = Object.keys(values).sort();
    
    // 2. Concatenate the values of each field in alphabetical order
    let concatString = '';
    for (const key of sortedKeys) {
      concatString += values[key];
    }
    
    // 3. Append the Integration Key
    concatString += this.integrationKey;
    
    // 4. Compute SHA512 hash and return uppercase hex
    return crypto.createHash('sha512').update(concatString).digest('hex').toUpperCase();
  }

  private verifyHash(values: Record<string, string>, incomingHash: string): boolean {
    const valuesWithoutHash = { ...values };
    delete valuesWithoutHash.hash;
    const computedHash = this.generateHash(valuesWithoutHash);
    return computedHash === incomingHash.toUpperCase();
  }

  async createPaymentLink(
    orderId: string,
    amount: number,
    currency: string,
    customerEmail: string,
    callbackUrl: string,
  ): Promise<PaymentLinkResult> {
    if (this.isSandbox || !this.integrationId || !this.integrationKey) {
      // Fallback to Mock if credentials are missing
      const mockGtw = new MockGateway();
      return mockGtw.createPaymentLink(orderId, amount, currency, customerEmail, callbackUrl);
    }

    const paymentReference = `PAY-NOW-${orderId}-${Date.now()}`;
    
    const fields: Record<string, string> = {
      id: this.integrationId,
      reference: paymentReference,
      amount: amount.toFixed(2),
      additionalinfo: `Order #${orderId} on WhatsApp Commerce`,
      returnurl: callbackUrl,
      resulturl: callbackUrl,
      authemail: customerEmail || 'customer@whatsappcommerce.com',
      status: 'Message',
    };

    fields.hash = this.generateHash(fields);

    try {
      const formUrlEncoded = new URLSearchParams(fields).toString();
      const response = await axios.post('https://www.paynow.co.zw/interface/initiatetransaction', formUrlEncoded, {
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      });

      const parsedResponse = new URLSearchParams(response.data);
      const status = parsedResponse.get('status');
      
      if (status?.toLowerCase() === 'ok') {
        const browserUrl = parsedResponse.get('browserurl') || '';
        const pollUrl = parsedResponse.get('pollurl') || '';
        
        return {
          paymentLink: browserUrl,
          paymentReference,
          gatewayReference: pollUrl, // we store the pollUrl as the gatewayReference
        };
      } else {
        const error = parsedResponse.get('error') || 'Unknown Paynow error';
        throw new Error(error);
      }
    } catch (err: any) {
      throw new Error(`Paynow transaction initiation failed: ${err.message}`);
    }
  }

  async verifyPayment(pollUrl: string): Promise<PaymentVerificationResult> {
    if (this.isSandbox || !pollUrl || !pollUrl.startsWith('http')) {
      return {
        status: 'SUCCESS',
        gatewayReference: 'MOCK-GTW-REF',
        amount: 0,
      };
    }

    try {
      const response = await axios.get(pollUrl);
      const parsedResponse = new URLSearchParams(response.data);
      
      // Verify hash if included
      const status = parsedResponse.get('status') || '';
      const amount = parseFloat(parsedResponse.get('amount') || '0');
      const paynowRef = parsedResponse.get('paynowreference') || '';
      
      const isSuccess = status.toLowerCase() === 'paid' || status.toLowerCase() === 'awaiting delivery';
      const isFailed = status.toLowerCase() === 'failed' || status.toLowerCase() === 'cancelled';
      
      return {
        status: isSuccess ? 'SUCCESS' : isFailed ? 'FAILED' : 'PENDING',
        gatewayReference: paynowRef,
        amount,
        rawResponse: response.data,
      };
    } catch (err: any) {
      return {
        status: 'PENDING',
        rawResponse: err.message,
      };
    }
  }

  async testConnection(): Promise<{ success: boolean; message: string }> {
    if (this.isSandbox || !this.integrationId || !this.integrationKey) {
      return { success: true, message: 'Paynow Sandbox configured successfully (Mock active)' };
    }
    try {
      const paymentReference = `TEST-CONN-${Date.now()}`;
      const fields: Record<string, string> = {
        id: this.integrationId,
        reference: paymentReference,
        amount: '1.00',
        additionalinfo: 'Connection Test',
        returnurl: 'http://localhost:3001',
        resulturl: 'http://localhost:3001',
        authemail: 'test@whatsappcommerce.com',
        status: 'Message',
      };
      fields.hash = this.generateHash(fields);
      const formUrlEncoded = new URLSearchParams(fields).toString();
      const response = await axios.post('https://www.paynow.co.zw/interface/initiatetransaction', formUrlEncoded, {
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      });
      const parsedResponse = new URLSearchParams(response.data);
      const status = parsedResponse.get('status');
      if (status?.toLowerCase() === 'ok' || parsedResponse.get('browserurl')) {
        return { success: true, message: 'Connected successfully to Paynow Production API!' };
      } else {
        const error = parsedResponse.get('error') || 'Unknown error';
        return { success: false, message: `Paynow returned error: ${error}` };
      }
    } catch (err: any) {
      return { success: false, message: `Paynow connection failed: ${err.message}` };
    }
  }

  async makeSeamlessPayment(
    _orderId: string,
    _amount: number,
    _currency: string,
    _ecocashNumber: string,
    _customerEmail: string,
    _reason: string,
    _callbackUrl: string,
  ): Promise<SeamlessPaymentResult> {
    // Paynow does not support seamless EcoCash payments natively.
    // Fall back to mock for sandbox/development.
    const mock = new MockGateway();
    return mock.makeSeamlessPayment(_orderId, _amount, _currency, _ecocashNumber, _customerEmail, _reason, _callbackUrl);
  }
}
