const crypto = require('crypto');
const axios = require('axios');
const { Payment, ChitGroup, GroupMember, User } = require('../models');
const { Op } = require('sequelize');
const PaymentReconciliationService = require('./payment-reconciliation-service');

/**
 * PhonePe Transaction Sync Service
 * Automatically pulls PhonePe transaction history and matches to payment records
 */
class PhonePeTransactionSyncService {
  constructor() {
    this.merchantId = process.env.PHONEPE_MERCHANT_ID || 'YOUR_MERCHANT_ID';
    this.saltKey = process.env.PHONEPE_SALT_KEY || 'YOUR_SALT_KEY';
    this.saltIndex = process.env.PHONEPE_SALT_INDEX || '1';
    this.apiEndpoint = process.env.PHONEPE_ENV === 'production'
      ? 'https://api.phonepe.com/apis/hermes'
      : 'https://api-preprod.phonepe.com/apis/pg-sandbox';
  }

  /**
   * Generate checksum for PhonePe API
   */
  generateChecksum(payload, endpoint) {
    const base64Payload = Buffer.from(JSON.stringify(payload)).toString('base64');
    const string = base64Payload + endpoint + this.saltKey;
    const sha256 = crypto.createHash('sha256').update(string).digest('hex');
    return sha256 + '###' + this.saltIndex;
  }

  /**
   * Fetch transactions from PhonePe for a date range
   */
  async fetchTransactions(startDate, endDate) {
    // Check if PhonePe Gateway is configured
    if (this.merchantId === 'YOUR_MERCHANT_ID' || !this.merchantId || this.merchantId.length < 5) {
      console.log('ℹ️ [PhonePe Sync] PhonePe Gateway not configured - using Direct UPI instead');
      console.log('ℹ️ [PhonePe Sync] For Direct UPI payments, use the webhook-based reconciliation');
      return {
        success: true,
        transactions: [],
        message: 'PhonePe Gateway not configured. Using Direct UPI payment system.',
        usingDirectUPI: true,
      };
    }

    try {
      const payload = {
        merchantId: this.merchantId,
        startDate: startDate.toISOString().split('T')[0], // YYYY-MM-DD
        endDate: endDate.toISOString().split('T')[0],
      };

      const endpoint = '/pg/v1/transactions';
      const checksum = this.generateChecksum(payload, endpoint);
      const base64Payload = Buffer.from(JSON.stringify(payload)).toString('base64');

      const response = await axios.post(
        `${this.apiEndpoint}${endpoint}`,
        { request: base64Payload },
        {
          headers: {
            'Content-Type': 'application/json',
            'X-VERIFY': checksum,
          },
        }
      );

      if (response.data.success) {
        return {
          success: true,
          transactions: response.data.data.transactions || [],
        };
      } else {
        console.error('Failed to fetch transactions:', response.data);
        return {
          success: false,
          message: response.data.message,
        };
      }
    } catch (error) {
      console.error('Error fetching PhonePe transactions:', error);
      return {
        success: false,
        message: error.response?.data?.message || error.message,
      };
    }
  }

  /**
   * Smart matching algorithm for transactions to members
   * Matches based on: amount, date, member phone, remarks
   */
  async matchTransaction(transaction, managerId) {
    const { amount, payerPhone, payerName, remarks, transactionDate } = transaction;
    const amountInRupees = amount / 100; // Convert from paise

    try {
      // Get all active groups for this manager
      const groups = await ChitGroup.findAll({
        where: { manager_id: managerId, status: { [Op.in]: ['active', 'forming'] } },
        include: [{
          model: GroupMember,
          as: 'GroupMembers',
          where: { status: 'active' },
          include: [{
            model: User,
            attributes: ['id', 'full_name', 'mobile_number'],
          }],
        }],
      });

      const matchResults = [];

      for (const group of groups) {
        const expectedAmount = parseFloat(group.monthly_installment);
        
        // Check if amount matches (within ₹10 tolerance)
        if (Math.abs(amountInRupees - expectedAmount) <= 10) {
          // Try to match by phone number
          const membersByPhone = group.GroupMembers.filter(gm => {
            const memberPhone = gm.User?.mobile_number?.replace(/\D/g, '').slice(-10);
            const txnPhone = payerPhone?.replace(/\D/g, '').slice(-10);
            return memberPhone && txnPhone && memberPhone === txnPhone;
          });

          if (membersByPhone.length > 0) {
            for (const member of membersByPhone) {
              matchResults.push({
                confidence: 'high',
                group,
                member,
                matchedBy: 'phone+amount',
                score: 95,
              });
            }
          } else {
            // Try to match by name
            const membersByName = group.GroupMembers.filter(gm => {
              const memberName = gm.User?.full_name?.toLowerCase();
              const txnName = payerName?.toLowerCase();
              return memberName && txnName && (
                memberName.includes(txnName) || txnName.includes(memberName)
              );
            });

            if (membersByName.length > 0) {
              for (const member of membersByName) {
                matchResults.push({
                  confidence: 'medium',
                  group,
                  member,
                  matchedBy: 'name+amount',
                  score: 75,
                });
              }
            }
          }

          // Try to match by UPI reference in remarks
          if (remarks) {
            const upiRefMatch = PaymentReconciliationService.parseUPIReference(remarks);
            if (upiRefMatch) {
              const member = group.GroupMembers.find(gm => 
                gm.User?.id.startsWith(upiRefMatch.userIdPrefix)
              );

              if (member) {
                matchResults.push({
                  confidence: 'very_high',
                  group,
                  member,
                  month: upiRefMatch.month,
                  year: upiRefMatch.year,
                  matchedBy: 'upi_reference',
                  score: 99,
                });
              }
            }
          }

          // If no specific member match but amount matches, flag for review
          if (matchResults.length === 0) {
            matchResults.push({
              confidence: 'low',
              group,
              member: null,
              matchedBy: 'amount_only',
              score: 50,
            });
          }
        }
      }

      // Sort by confidence score
      matchResults.sort((a, b) => b.score - a.score);

      return {
        success: true,
        matches: matchResults,
        transaction,
      };
    } catch (error) {
      console.error('Error matching transaction:', error);
      return {
        success: false,
        message: error.message,
      };
    }
  }

  /**
   * Sync transactions for a specific manager
   */
  async syncTransactionsForManager(managerId, daysBack = 7) {
    try {
      const endDate = new Date();
      const startDate = new Date();
      startDate.setDate(startDate.getDate() - daysBack);

      console.log(`Syncing PhonePe transactions for manager ${managerId}...`);
      console.log(`Date range: ${startDate.toISOString()} to ${endDate.toISOString()}`);

      // Fetch transactions from PhonePe
      const result = await this.fetchTransactions(startDate, endDate);

      // If using Direct UPI (no PhonePe Gateway configured)
      if (result.usingDirectUPI) {
        console.log('ℹ️ [PhonePe Sync] Using Direct UPI - No gateway sync needed');
        return {
          success: true,
          message: 'Direct UPI payment system active. Payments auto-detected via webhooks.',
          results: {
            total: 0,
            matched: 0,
            autoRecorded: 0,
            needsReview: 0,
            failed: 0,
            usingDirectUPI: true,
          },
        };
      }

      if (!result.success) {
        return {
          success: false,
          message: result.message,
        };
      }

      const transactions = result.transactions;
      console.log(`Fetched ${transactions.length} transactions`);

      const syncResults = {
        total: transactions.length,
        matched: 0,
        autoRecorded: 0,
        needsReview: 0,
        failed: 0,
        suggestions: [],
      };

      // Process each transaction
      for (const transaction of transactions) {
        // Skip if already processed
        const existing = await Payment.findOne({
          where: { transaction_id: transaction.id },
        });

        if (existing) {
          console.log(`Transaction ${transaction.id} already recorded`);
          continue;
        }

        // Try to match
        const matchResult = await this.matchTransaction(transaction, managerId);

        if (matchResult.success && matchResult.matches.length > 0) {
          const bestMatch = matchResult.matches[0];
          syncResults.matched++;

          if (bestMatch.confidence === 'very_high' || bestMatch.confidence === 'high') {
            // Auto-record high confidence matches
            const txnDate = new Date(transaction.transactionDate);
            const month = bestMatch.month || txnDate.getMonth() + 1;
            const year = bestMatch.year || txnDate.getFullYear();

            await Payment.create({
              group_id: bestMatch.group.id,
              user_id: bestMatch.member.User.id,
              month,
              year,
              amount: transaction.amount / 100,
              payment_method: 'upi',
              transaction_id: transaction.id,
              status: 'success',
              paid_at: txnDate,
              notes: `Auto-synced from PhonePe - ${transaction.payerPhone || transaction.payerName} - ${bestMatch.matchedBy}`,
            });

            syncResults.autoRecorded++;
          } else {
            // Add to review queue for medium/low confidence
            syncResults.needsReview++;
            syncResults.suggestions.push({
              transaction,
              match: bestMatch,
              requiresReview: true,
            });
          }
        } else {
          syncResults.failed++;
        }
      }

      return {
        success: true,
        results: syncResults,
      };
    } catch (error) {
      console.error('Error syncing transactions:', error);
      return {
        success: false,
        message: error.message,
      };
    }
  }

  /**
   * Get transactions that need manual review
   */
  async getTransactionsNeedingReview(managerId) {
    try {
      // Fetch recent transactions
      const endDate = new Date();
      const startDate = new Date();
      startDate.setDate(startDate.getDate() - 30); // Last 30 days

      const result = await this.fetchTransactions(startDate, endDate);

      // If using Direct UPI
      if (result.usingDirectUPI) {
        console.log('ℹ️ [PhonePe Sync] Direct UPI active - no review queue needed');
        return {
          success: true,
          reviewQueue: [],
          count: 0,
          message: 'Using Direct UPI - payments auto-detected via webhooks',
        };
      }

      if (!result.success) {
        return { success: false, message: result.message };
      }

      const reviewQueue = [];

      for (const transaction of result.transactions) {
        // Skip already recorded
        const existing = await Payment.findOne({
          where: { transaction_id: transaction.id },
        });
        if (existing) continue;

        // Try to match
        const matchResult = await this.matchTransaction(transaction, managerId);

        if (matchResult.success && matchResult.matches.length > 0) {
          const bestMatch = matchResult.matches[0];
          
          // Only include medium/low confidence matches for review
          if (bestMatch.confidence === 'medium' || bestMatch.confidence === 'low') {
            reviewQueue.push({
              transaction,
              matches: matchResult.matches,
              suggestedMatch: bestMatch,
            });
          }
        }
      }

      return {
        success: true,
        reviewQueue,
        count: reviewQueue.length,
      };
    } catch (error) {
      console.error('Error getting review queue:', error);
      return {
        success: false,
        message: error.message,
      };
    }
  }

  /**
   * Approve a suggested match
   */
  async approveSuggestedMatch(transactionId, groupId, userId, month, year, amount) {
    try {
      const payment = await Payment.create({
        group_id: groupId,
        user_id: userId,
        month,
        year,
        amount,
        payment_method: 'upi',
        transaction_id: transactionId,
        status: 'success',
        paid_at: new Date(),
        notes: 'Manager approved auto-sync suggestion',
      });

      return {
        success: true,
        payment,
      };
    } catch (error) {
      console.error('Error approving match:', error);
      return {
        success: false,
        message: error.message,
      };
    }
  }
}

module.exports = PhonePeTransactionSyncService;

