import { GatewaySecretConfig, ServerTransaction } from './types';

export class BkashService {
  /**
   * Determine bKash base URL based on mode and custom api_url
   */
  private static getBaseUrl(config: GatewaySecretConfig): string {
    if (config.api_url && config.api_url.trim()) {
      return config.api_url.trim().replace(/\/+$/, '');
    }
    return config.mode === 'live'
      ? 'https://tokenized.pay.bka.sh/v1.2.0-beta/tokenized/checkout'
      : 'https://tokenized.sandbox.bka.sh/v1.2.0-beta/tokenized/checkout';
  }

  /**
   * Request bKash Grant Token (Server-to-Server Authentication)
   */
  public static async grantToken(config: GatewaySecretConfig): Promise<string | null> {
    if (!config.app_key || !config.app_secret || !config.username || !config.password) {
      return null;
    }

    try {
      const baseUrl = this.getBaseUrl(config);
      const res = await fetch(`${baseUrl}/token/grant`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          username: config.username,
          password: config.password,
        },
        body: JSON.stringify({
          app_key: config.app_key,
          app_secret: config.app_secret,
        }),
      });

      if (!res.ok) {
        return null;
      }

      const data: any = await res.json();
      return data.id_token || null;
    } catch {
      return null;
    }
  }

  /**
   * Create Payment with bKash API
   */
  public static async createPayment(
    config: GatewaySecretConfig,
    txn: ServerTransaction,
    callbackUrl: string
  ): Promise<{ success: boolean; paymentId?: string; bkashURL?: string; message?: string }> {
    // If in Live mode, require actual credentials
    if (config.mode === 'live') {
      const token = await this.grantToken(config);
      if (!token) {
        return {
          success: false,
          message: 'bKash authentication failed. Please check live credentials in Admin Panel.',
        };
      }

      try {
        const baseUrl = this.getBaseUrl(config);
        const res = await fetch(`${baseUrl}/create`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            Authorization: token,
            'X-APP-Key': config.app_key || '',
          },
          body: JSON.stringify({
            mode: '0011',
            payerReference: txn.listing_id,
            callbackURL: callbackUrl,
            amount: txn.amount.toString(),
            currency: 'BDT',
            intent: 'sale',
            merchantInvoiceNumber: txn.transaction_id,
          }),
        });

        const data: any = await res.json();
        if (data.statusCode === '0000' && data.bkashURL) {
          return {
            success: true,
            paymentId: data.paymentID,
            bkashURL: data.bkashURL,
          };
        }

        return {
          success: false,
          message: data.statusMessage || 'bKash payment initialization rejected.',
        };
      } catch (err: any) {
        return {
          success: false,
          message: err.message || 'Failed to connect to bKash live API.',
        };
      }
    }

    // In Sandbox / Test Mode:
    // If real sandbox token is obtainable, use live sandbox; otherwise return sandbox interactive simulation URL
    const token = await this.grantToken(config);
    if (token) {
      try {
        const baseUrl = this.getBaseUrl(config);
        const res = await fetch(`${baseUrl}/create`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            Authorization: token,
            'X-APP-Key': config.app_key || '',
          },
          body: JSON.stringify({
            mode: '0011',
            payerReference: txn.listing_id,
            callbackURL: callbackUrl,
            amount: txn.amount.toString(),
            currency: 'BDT',
            intent: 'sale',
            merchantInvoiceNumber: txn.transaction_id,
          }),
        });

        const data: any = await res.json();
        if (data.statusCode === '0000' && data.bkashURL) {
          return {
            success: true,
            paymentId: data.paymentID,
            bkashURL: data.bkashURL,
          };
        }
      } catch {
        // Fallback to sandbox simulator
      }
    }

    return {
      success: true,
      paymentId: `BKASH_DEMO_${txn.transaction_id}`,
      bkashURL: `/payment-sandbox?txn=${txn.transaction_id}&gw=bkash`,
    };
  }

  /**
   * Execute Payment with bKash API on Return / Callback
   */
  public static async executePayment(
    config: GatewaySecretConfig,
    paymentId: string
  ): Promise<{ success: boolean; data?: any; trxID?: string; message?: string }> {
    if (config.mode === 'live' || (config.app_key && config.app_secret && !paymentId.startsWith('BKASH_DEMO_'))) {
      const token = await this.grantToken(config);
      if (!token) {
        return { success: false, message: 'Failed to obtain bKash execution token.' };
      }

      try {
        const baseUrl = this.getBaseUrl(config);
        const res = await fetch(`${baseUrl}/execute`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            Authorization: token,
            'X-APP-Key': config.app_key || '',
          },
          body: JSON.stringify({ paymentID: paymentId }),
        });

        const data: any = await res.json();
        if (data.statusCode === '0000' && data.transactionStatus === 'Completed') {
          return {
            success: true,
            trxID: data.trxID,
            data,
          };
        }

        return {
          success: false,
          message: data.statusMessage || 'bKash transaction was not completed.',
          data,
        };
      } catch (err: any) {
        return { success: false, message: err.message || 'bKash execution network error.' };
      }
    }

    // Sandbox simulation completion
    return {
      success: true,
      trxID: `BKASH_TRX_${Math.floor(10000000 + Math.random() * 90000000)}`,
      data: { simulated: true, mode: 'sandbox' },
    };
  }

  /**
   * Query / Verify Payment with bKash API
   */
  public static async queryPayment(
    config: GatewaySecretConfig,
    paymentId: string
  ): Promise<{ verified: boolean; trxID?: string; raw?: any }> {
    if (paymentId.startsWith('BKASH_DEMO_')) {
      return { verified: true, trxID: `SIM_${paymentId}` };
    }

    const token = await this.grantToken(config);
    if (!token) return { verified: false };

    try {
      const baseUrl = this.getBaseUrl(config);
      const res = await fetch(`${baseUrl}/payment/status`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Authorization: token,
          'X-APP-Key': config.app_key || '',
        },
        body: JSON.stringify({ paymentID: paymentId }),
      });

      const data: any = await res.json();
      const verified = data.statusCode === '0000' && data.transactionStatus === 'Completed';
      return {
        verified,
        trxID: data.trxID,
        raw: data,
      };
    } catch {
      return { verified: false };
    }
  }
}
