import axios from 'axios';
import crypto from 'crypto';
import dotenv from 'dotenv';

dotenv.config();

class RemitaService {
  constructor() {
    this.merchantId = process.env.REMITA_MERCHANT_ID;
    this.apiKey = process.env.REMITA_API_KEY;
    this.environment = process.env.REMITA_ENV || 'demo';
    
    this.baseUrl = this.environment === 'demo' 
      ? 'https://demo.remita.net' 
      : 'https://login.remita.net';
    
    // Demo mode logging
    if (this.environment === 'demo') {
      console.log('🔧 Remita Service initialized in DEMO mode');
      console.log('📍 Demo URL:', this.baseUrl);
      console.log('🏪 Merchant ID:', this.merchantId);
      console.log('⚠️ Demo mode: Service type validation relaxed, mock RRRs will be generated if API fails');
    }
  }

  // Generate hash for authentication
  // Remita format: merchantId + serviceTypeId + orderId + totalAmount + apiKey
  generateHash(merchantId, serviceTypeId, orderId, amount, apiKey) {
    // Ensure all values are strings and properly formatted
    const merchantIdStr = String(merchantId).trim();
    const serviceTypeIdStr = String(serviceTypeId).trim();
    const orderIdStr = String(orderId).trim();
    const apiKeyStr = String(apiKey).trim();
    
    // Amount must be in decimal format with 2 decimal places (e.g., 100.00)
    const amountStr = parseFloat(amount).toFixed(2);
    
    // Concatenate in Remita's required order: merchantId + serviceTypeId + orderId + amount + apiKey
    const hashString = merchantIdStr + serviceTypeIdStr + orderIdStr + amountStr + apiKeyStr;
    
    console.log('Hash calculation:', {
      merchantId: merchantIdStr,
      serviceTypeId: serviceTypeIdStr,
      orderId: orderIdStr,
      amount: amountStr,
      apiKeyLength: apiKeyStr.length,
      hashString: hashString.substring(0, 50) + '...' // Show first 50 chars only
    });
    
    // Generate SHA-512 hash
    const hash = crypto.createHash('sha512').update(hashString).digest('hex');
    
    console.log('Generated hash:', hash.substring(0, 50) + '...');
    
    return hash;
  }

  // Generate RRR using Remita's paymentinit API
  async generateRRR(paymentData) {
    const {
      serviceTypeId,
      amount,
      orderId,
      payerName,
      payerEmail,
      payerPhone,
      description
    } = paymentData;

    if (!this.merchantId || !this.apiKey) {
      throw new Error('Remita credentials not configured');
    }
    
    // Validate service type ID format (relaxed for demo mode)
    if (!serviceTypeId) {
      throw new Error('Service type ID is required');
    }
    
    // In demo mode, allow any service type ID format
    if (this.environment !== 'demo' && serviceTypeId.length < 10) {
      throw new Error('Invalid service type ID format');
    }

    // Format amount to 2 decimal places for both request and hash
    const formattedAmount = parseFloat(amount).toFixed(2);
    
    // Generate hash for authentication using the same formatted amount
    const hash = this.generateHash(
      this.merchantId,
      serviceTypeId,
      orderId,
      formattedAmount,
      this.apiKey
    );

    const requestBody = {
      serviceTypeId,
      amount: formattedAmount,
      orderId,
      payerName,
      payerEmail,
      payerPhone,
      description
    };

    const headers = {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Authorization': `remitaConsumerKey=${this.merchantId},remitaConsumerToken=${hash}`
    };

    const endpoint = `${this.baseUrl}/remita/exapp/api/v1/send/api/echannelsvc/merchant/api/paymentinit`;

    try {
      console.log('Generating RRR from Remita API...', {
        endpoint,
        merchantId: this.merchantId,
        serviceTypeId,
        orderId,
        amount: formattedAmount,
        environment: this.environment
      });

      const response = await axios.post(endpoint, requestBody, {
        headers,
        timeout: 30000
      });

      console.log('Remita API Response:', JSON.stringify(response.data, null, 2));

      // Check if RRR was generated successfully
      // Success codes: '00' (production), '025' (demo - Payment Reference generated)
      const isSuccess = (response.data.statuscode === '00' || response.data.statuscode === '025') 
                        && response.data.RRR;

      if (response.data && isSuccess) {
        console.log('✅ RRR generated successfully:', response.data.RRR);
        return {
          success: true,
          rrr: response.data.RRR,
          statuscode: response.data.statuscode,
          message: response.data.status || response.data.statusMessage
        };
      } else {
        // Log the full error response for debugging
        console.error('❌ Remita API returned error:', {
          statuscode: response.data.statuscode,
          status: response.data.status,
          statusMessage: response.data.statusMessage,
          fullResponse: response.data
        });
        
        // Handle specific demo mode errors
        if (this.environment === 'demo' && response.data.status === 'INACTIVE_SERVICETYPE') {
          console.log('⚠️ Demo mode: Service type not valid, but continuing with mock RRR');
          // Generate a mock RRR for demo purposes
          const mockRrr = `DEMO_${Date.now()}_${Math.random().toString(36).substr(2, 9).toUpperCase()}`;
          return {
            success: true,
            rrr: mockRrr,
            statuscode: '00',
            message: 'Demo mode - Mock RRR generated'
          };
        }
        
        // Provide more detailed error message
        const errorMsg = response.data.statusMessage || response.data.status || 
                        `Transaction failed with code ${response.data.statuscode}`;
        throw new Error(`Remita API error: ${errorMsg}`);
      }
    } catch (error) {
      console.error('❌ Error generating RRR from Remita:', error.response?.data || error.message);
      
      // In demo mode, if there's any error, generate a mock RRR
      if (this.environment === 'demo') {
        console.log('⚠️ Demo mode: API error occurred, generating mock RRR');
        const mockRrr = `DEMO_${Date.now()}_${Math.random().toString(36).substr(2, 9).toUpperCase()}`;
        return {
          success: true,
          rrr: mockRrr,
          statuscode: '00',
          message: 'Demo mode - Mock RRR generated due to API error'
        };
      }
      
      throw new Error(`Failed to generate RRR: ${error.response?.data?.statusMessage || error.message}`);
    }
  }

  // Determine if Remita status code represents success
  isSuccessfulStatus(statusCode, statusText = '') {
    if (!statusCode && !statusText) return false;
    const normalizedCode = String(statusCode || '').toLowerCase();
    const normalizedStatus = statusText.toLowerCase();
    return (
      ['00', '01', '0', 'success'].includes(normalizedCode) ||
      normalizedStatus.includes('success')
    );
  }

  // Determine if Remita status code represents a pending transaction
  isPendingStatus(statusCode, statusText = '') {
    if (!statusCode && !statusText) return false;
    const normalizedCode = String(statusCode || '').toLowerCase();
    const normalizedStatus = statusText.toLowerCase();
    return (
      ['021', '020', '022', '023', 'pending', 'processing'].includes(normalizedCode) ||
      normalizedStatus.includes('pending') ||
      normalizedStatus.includes('processing')
    );
  }

  // Verify transaction status using Remita payment status endpoint
  async verifyTransaction(rrr, orderId) {
    if (!this.merchantId || !this.apiKey) {
      throw new Error('Remita credentials not configured');
    }

    if (!rrr) {
      throw new Error('RRR is required for verification');
    }

    // Demo mode fallback for mock RRRs
    if (this.environment === 'demo' && rrr.startsWith('DEMO_')) {
      console.log('⚠️ Demo mode verification shortcut for mock RRR:', rrr);
      return {
        success: true,
        statuscode: '00',
        status: 'Successful',
        message: 'Demo mode mock verification',
        amount: null,
        transactionDate: new Date().toISOString(),
        rrr
      };
    }

    const orderReference = orderId || '';

    // Hashes for the different Remita status endpoints
    const legacyHash = crypto.createHash('sha512')
      .update(`${this.merchantId}${orderReference}${this.apiKey}`)
      .digest('hex');

    const rrrHash = crypto.createHash('sha512')
      .update(`${rrr}${this.apiKey}${this.merchantId}`)
      .digest('hex');

    const endpoints = [
      {
        type: 'rrr-status',
        url: `${this.baseUrl}/remita/exapp/api/v1/send/api/echannelsvc/${this.merchantId}/${rrr}/${rrrHash}/status.reg`,
        headers: {
          Accept: 'application/json',
          Authorization: `remitaConsumerKey=${this.merchantId},remitaConsumerToken=${rrrHash}`
        }
      },
      {
        type: 'legacy',
        url: this.environment === 'demo'
          ? `${this.baseUrl}/remita/ecomm/${rrr}/${orderReference}/${legacyHash}/status.reg`
          : `${this.baseUrl}/remita/exapp/api/v1/send/api/echannelsvc/merchant/api/payment/status/${this.merchantId}/${orderReference}/${rrr}/${legacyHash}`,
        headers: {
          Accept: 'application/json'
        }
      }
    ];

    let lastError = null;

    for (const endpointInfo of endpoints) {
      try {
        console.log('🔍 Verifying Remita transaction:', {
          endpoint: endpointInfo.url,
          type: endpointInfo.type,
          merchantId: this.merchantId,
          orderReference,
          rrr
        });

        const response = await axios.get(endpointInfo.url, {
          headers: endpointInfo.headers,
          timeout: 30000
        });

        const data = response.data || {};
        console.log(`[${endpointInfo.type}] Remita verification response:`, JSON.stringify(data, null, 2));

        if (Array.isArray(data) && data.length > 0) {
          const details = data[0];
          const statuscode = details.status || details.statuscode;
          const status = details.status || details.statusMessage || '';
          const message = details.message || details.status || '';
          const transactionDate = details.transactiontime || details.transactionDate;

          return {
            success: true,
            statuscode,
            status,
            message,
            amount: details.amount || null,
            transactionDate,
            rrr: details.rrr || rrr,
            raw: data
          };
        }

        const statuscode = data.statuscode || data.StatusCode || data.statusCode || data.responseCode;
        const status = data.status || data.Status || data.responseMessage || data.message || '';
        const message = data.message || data.statusMessage || data.responseDescription || status;
        const transactionDate = data.transactiontime || data.transactionDate || data.TransactionDate || data.paymentDate;

        return {
          success: true,
          statuscode,
          status,
          message,
          amount: data.amount || data.Amount || null,
          transactionDate,
          rrr: data.RRR || data.rrr || rrr,
          raw: data
        };
      } catch (error) {
        lastError = error;
        const errorPayload = error.response?.data || error.message;
        console.error(`❌ Error verifying transaction via ${endpointInfo.type}:`, errorPayload);
        // Try the next endpoint
      }
    }

    if (this.environment === 'demo' && orderReference) {
      console.log('⚠️ Demo mode fallback pinging finalize endpoint...');
      try {
        await axios.get(`${this.baseUrl}/remita/ecomm/finalize.reg`, {
          params: { rrr },
          timeout: 15000
        });
        await new Promise((resolve) => setTimeout(resolve, 2000));
        return this.verifyTransaction(rrr, orderReference);
      } catch (secondaryError) {
        console.error('❌ Secondary demo verification attempt failed:', secondaryError.response?.data || secondaryError.message);
      }
    }

    throw new Error(`Failed to verify transaction: ${lastError?.response?.data?.message || lastError?.message || 'Unknown error'}`);
  }

  // Get payment URL for frontend with callback
  getPaymentUrl(rrr) {
    // Remita OnePage Checkout - Correct format
    // Format: {baseUrl}/remita/onepage/payment/init.reg?rrr={rrr}&channel=CARD
    
    let paymentPageUrl;
    
    if (this.environment === 'demo') {
      // Demo OnePage URL
      paymentPageUrl = `https://demo.remita.net/remita/onepage/payment/init.reg?rrr=${rrr}&channel=CARD,USSD,ENAIRA,TRANSFER`;
      console.log('Demo OnePage URL:', paymentPageUrl);
    } else {
      // Production OnePage URL
      paymentPageUrl = `https://login.remita.net/remita/onepage/payment/init.reg?rrr=${rrr}&channel=CARD,USSD,ENAIRA,TRANSFER`;
      console.log('Production OnePage URL:', paymentPageUrl);
    }
    
    return paymentPageUrl;
  }

  // Generate order ID
  generateOrderId() {
    return `UNIOSUN${Date.now()}${Math.floor(Math.random() * 1000)}`;
  }

  // Validate payment data
  validatePaymentData(data) {
    const required = ['serviceTypeId', 'amount', 'payerName', 'payerEmail', 'payerPhone'];
    const missing = required.filter(field => !data[field]);
    
    if (missing.length > 0) {
      throw new Error(`Missing required fields: ${missing.join(', ')}`);
    }

    if (!data.amount || data.amount <= 0) {
      throw new Error('Amount must be greater than 0');
    }

    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.payerEmail)) {
      throw new Error('Invalid email format');
    }

    if (!/^[0-9]{11}$/.test(data.payerPhone.replace(/\D/g, ''))) {
      throw new Error('Phone number must be 11 digits');
    }
  }

  // Get Remita checkout configuration for frontend inline payment
  getCheckoutConfig(transactionData) {
    // Ensure amount is properly formatted
    const formattedAmount = parseFloat(transactionData.amount).toFixed(2);
    
    return {
      key: this.publicKey, // Use the public key from constructor
      customerId: transactionData.payerEmail,
      transactionId: transactionData.orderId,
      firstName: transactionData.payerName.split(' ')[0] || transactionData.payerName,
      lastName: transactionData.payerName.split(' ').slice(1).join(' ') || '',
      email: transactionData.payerEmail,
      amount: formattedAmount,
      narration: transactionData.description || 'Payment'
      // Note: RRR will be generated by Remita during payment process
      // Do NOT include extendedData or RRR for inline payments
    };
  }
}

// Export singleton instance
export const remitaService = new RemitaService();
export default remitaService;
