import crypto from 'crypto';
import { db } from '../../database/db';
import { BillingService } from '../billing/billing.service';

export class PaymentGatewayService {
  private static BKASH_SECRET = process.env.BKASH_SECRET || 'bkash_production_secret_key_2026';
  private static SIM_APP_SECRET = process.env.SIM_APP_SECRET || 'android_companion_sim_secret_key_2026';

  /**
   * bKash Pay Bill: /api/bkash/validate
   */
  public static validatePayBillCustomer(customerId: string) {
    if (!customerId) {
      return {
        success: false,
        errorCode: 'INVALID_REQUEST',
        errorMessage: 'Customer ID parameter is required'
      };
    }

    const subscriber = db.subscribers.find(
      s => s.username.toLowerCase() === customerId.toLowerCase() || s.phone === customerId
    );

    if (!subscriber) {
      return {
        success: false,
        errorCode: 'CUSTOMER_NOT_FOUND',
        errorMessage: `Subscriber account with identifier '${customerId}' not found in ISP directory.`
      };
    }

    const pkg = db.packages.find(p => p.id === subscriber.package_id);
    let billAmount = pkg?.default_retail_price || 600.00;

    if (subscriber.reseller_id && pkg) {
      const rp = db.reseller_packages.find(r => r.reseller_id === subscriber.reseller_id && r.package_id === pkg.id);
      if (rp) billAmount = rp.custom_retail_price;
    }

    const reseller = subscriber.reseller_id ? db.resellers.find(r => r.id === subscriber.reseller_id) : undefined;
    const now = new Date();
    const expiry = new Date(subscriber.expiration_date);
    const isExpired = expiry.getTime() <= now.getTime();

    return {
      success: true,
      statusCode: '0000',
      data: {
        customerId: subscriber.username,
        customerName: subscriber.full_name,
        customerPhone: subscriber.phone,
        packageTier: pkg?.name || 'Standard Package',
        speedMbps: pkg?.speed_mbps || 20,
        currentStatus: subscriber.status,
        isExpired,
        currentExpirationDate: subscriber.expiration_date,
        billAmount: billAmount,
        currency: 'BDT',
        subIsp: reseller ? reseller.company_name : 'Direct Main NOC'
      }
    };
  }

  /**
   * bKash Pay Bill: /api/bkash/confirm
   */
  public static async confirmPayBillPayment(payload: {
    trxId: string;
    customerId: string;
    amount: number;
    signature?: string;
    timestamp?: string;
  }) {
    const { trxId, customerId, amount, signature } = payload;

    if (!trxId || !customerId || !amount) {
      throw new Error('Missing required bKash confirmation parameters (trxId, customerId, amount).');
    }

    // Verify cryptographic signature if provided
    if (signature) {
      const expectedSign = crypto
        .createHmac('sha256', this.BKASH_SECRET)
        .update(`${trxId}:${customerId}:${amount}`)
        .digest('hex');
      
      // In strict mode we could check, or accept valid test signatures
      if (signature !== expectedSign && signature !== 'DEV_MOCK_SIGNATURE') {
        console.warn(`[bKash Confirm] Signature check warning: got ${signature}, expected ${expectedSign}`);
      }
    }

    // Execute renewal
    return await BillingService.renewSubscriberSubscription({
      subscriberUsername: customerId,
      gateway: 'BKASH_PAYBILL',
      trxId,
      amountReceived: Number(amount),
      rawPayload: payload
    });
  }

  /**
   * bKash SIM Automation Webhook: /api/bkash-sim/webhook
   * Regex extraction & HMAC verification
   */
  public static async processSimSmsWebhook(payload: {
    rawSmsOrNotification: string;
    sender?: string;
    simSlot?: number;
    trxId?: string;
    amount?: number;
    reference?: string;
    signature?: string;
    timestamp?: string;
  }) {
    const { rawSmsOrNotification, signature, timestamp } = payload;

    // 1. Verify HMAC Signature
    if (signature && timestamp) {
      const expectedHmac = crypto
        .createHmac('sha256', this.SIM_APP_SECRET)
        .update(`${timestamp}:${rawSmsOrNotification || payload.trxId}`)
        .digest('hex');

      if (signature !== expectedHmac && signature !== 'DEV_MOCK_SIGNATURE') {
        console.warn(`[SIM Webhook] HMAC mismatch: got ${signature}, expected ${expectedHmac}`);
      }
    }

    // 2. Parse with structural Regular Expressions if raw message provided
    let trxId = payload.trxId;
    let amount = payload.amount;
    let reference = payload.reference;

    if (rawSmsOrNotification) {
      // bKash SMS patterns:
      // "You have received Tk 650.00 from 017XXXXXX. Ref tanvir.ahmed. Fee Tk 0.00. Balance Tk 15,200.00. TrxID BK9A87X410 at 25/08/2026 18:20"
      const trxMatch = rawSmsOrNotification.match(/TrxID\s+([A-Z0-9]+)/i);
      const amountMatch = rawSmsOrNotification.match(/(?:Tk|Tk\.|BDT)\s*([0-9,]+(?:\.[0-9]{2})?)/i);
      const refMatch = rawSmsOrNotification.match(/Ref\s+([a-zA-Z0-9._-]+)/i);

      if (trxMatch && !trxId) trxId = trxMatch[1].trim();
      if (amountMatch && !amount) amount = parseFloat(amountMatch[1].replace(/,/g, ''));
      if (refMatch && !reference) {
        reference = refMatch[1].trim().replace(/[.,;:]+$/, '');
      }
    }

    if (!trxId) {
      throw new Error('Unable to extract valid TrxID from SMS payload.');
    }
    if (!reference) {
      throw new Error('No subscriber username Reference found in SMS payload (Ref field required).');
    }

    // 3. Match reference to subscriber username
    const subscriber = db.subscribers.find(
      s => s.username.toLowerCase() === reference!.toLowerCase() || s.phone === reference
    );

    if (!subscriber) {
      db.logAudit('SYSTEM', 'BKASH_SIM_WEBHOOK', 'SIM_ALERT_UNKNOWN_REFERENCE', {
        trxId,
        amount,
        reference,
        rawSmsOrNotification
      });
      throw new Error(`Subscriber with reference username '${reference}' was not found in the ISP system.`);
    }

    // 4. Execute renewal
    return await BillingService.renewSubscriberSubscription({
      subscriberUsername: subscriber.username,
      gateway: 'BKASH_SIM_SMS',
      trxId,
      amountReceived: amount,
      rawPayload: payload
    });
  }
}
