import { PaymentItem } from '../models/PaymentItem.js';
import { Transaction } from '../models/Transaction.js';
import { remitaService } from '../utils/remita.js';

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const verifyTransactionWithRetry = async (transaction, options = {}) => {
  const {
    maxAttempts = 3,
    delayMs = 5000,
    context = 'verification'
  } = options;

  let attempt = 0;
  let verification;

  while (attempt < maxAttempts) {
    attempt += 1;
    verification = await remitaService.verifyTransaction(transaction.rrr, transaction.order_id);

    const statusCode = verification.statuscode || verification.status;
    const statusText = verification.status || verification.message || '';
    const resolvedStatus = remitaService.isSuccessfulStatus(statusCode, statusText)
      ? 'completed'
      : remitaService.isPendingStatus(statusCode, statusText)
        ? 'pending'
        : 'failed';

    console.log(`🔁 Remita verification attempt ${attempt}/${maxAttempts} for ${transaction.order_id} returned ${resolvedStatus}`);

    if (resolvedStatus !== 'pending') {
      return verification;
    }

    if (attempt < maxAttempts) {
      console.log(`⏳ Waiting ${delayMs}ms before next verification attempt (${context})`);
      await sleep(delayMs);
    }
  }

  return verification;
};

const applyVerificationResult = async (transaction, verification, req, context) => {
  const statusCode = verification.statuscode || verification.status;
  const statusText = verification.status || verification.message || '';

  let nextStatus = 'failed';
  if (remitaService.isSuccessfulStatus(statusCode, statusText)) {
    nextStatus = 'completed';
  } else if (remitaService.isPendingStatus(statusCode, statusText)) {
    nextStatus = 'pending';
  }

  await Transaction.updateStatus(transaction.order_id, nextStatus, {
    status: statusCode,
    message: verification.message,
    transactionDate: verification.transactionDate || null
  });

  const updatedTransaction = await Transaction.getByOrderId(transaction.order_id);
  const transactionId = updatedTransaction?.id ?? transaction.id ?? null;

  await Transaction.logAction(
    transactionId,
    context,
    {
      status: nextStatus,
      remitaStatus: statusCode,
      remitaMessage: verification.message,
      verification
    },
    req
  );

  return { updatedTransaction, nextStatus };
};

// Get all active payment items
export const getPaymentItems = async (req, res) => {
  try {
    const items = await PaymentItem.getAllActive();
    res.json({
      success: true,
      data: items
    });
  } catch (error) {
    console.error('Error fetching payment items:', error);
    res.status(500).json({
      success: false,
      message: 'Failed to fetch payment items'
    });
  }
};

// Initiate payment
export const initiatePayment = async (req, res) => {
  try {
    const {
    payerName,
    payerEmail,
    payerPhone,
    payment_item_id,
      amount
    } = req.body;

    // Get payment item details
    const paymentItem = await PaymentItem.getById(payment_item_id);
    if (!paymentItem) {
      return res.status(404).json({
        success: false,
        message: 'Payment item not found'
      });
    }

    // Determine the amount to use
    let amountToUse;
    const itemAmount = parseFloat(paymentItem.amount);
    
    if (itemAmount === 0 || itemAmount === 0.0) {
      // For items with 0 amount, use the custom amount provided
      const customAmount = parseFloat(amount);
      if (!amount || isNaN(customAmount) || customAmount < 100) {
        return res.status(400).json({
          success: false,
          message: 'Amount is required and must be at least ₦100'
        });
      }
      amountToUse = customAmount;
    } else {
      // For items with fixed amount, validate it matches
      const providedAmount = parseFloat(amount);
      if (isNaN(providedAmount) || providedAmount !== itemAmount) {
        return res.status(400).json({
          success: false,
          message: 'Amount does not match payment item price'
        });
      }
      amountToUse = itemAmount;
    }

    // Generate order ID
    const orderId = remitaService.generateOrderId();

    // Prepare payment data for Remita
    const paymentData = {
      serviceTypeId: paymentItem.service_type_id,
      amount: amountToUse,
      orderId,
      payerName,
      payerEmail,
      payerPhone,
      description: `Payment for ${paymentItem.payment_item}`
    };

    // For redirect-based payments, generate RRR upfront
    console.log('🔄 Generating RRR for redirect-based payment...');
    
    const rrrResult = await remitaService.generateRRR({
      serviceTypeId: paymentItem.service_type_id,
      amount: amountToUse,
      orderId,
      payerName,
      payerEmail,
      payerPhone,
      description: `Payment for ${paymentItem.payment_item}`
    });

    if (!rrrResult.success) {
      return res.status(400).json({
        success: false,
        message: rrrResult.message || 'Failed to generate payment reference'
      });
    }

    console.log('✅ RRR generated successfully:', rrrResult.rrr);

    // Create transaction record with RRR
    const transactionRecord = {
      order_id: orderId,
      rrr: rrrResult.rrr,
      payer_name: payerName,
      payer_email: payerEmail,
      payer_phone: payerPhone,
      payment_item_id: payment_item_id,
      payment_item: paymentItem.payment_item,
      amount: amountToUse,
      service_type_id: paymentItem.service_type_id,
      status: 'pending'
    };

    await Transaction.create(transactionRecord);

    // Generate payment URL for redirect
    const paymentUrl = remitaService.getPaymentUrl(rrrResult.rrr);

    console.log('🔧 Payment URL generated:', paymentUrl);

    // Log the action
    await Transaction.logAction(null, 'payment_initiated', {
      orderId,
      rrr: rrrResult.rrr,
      paymentItem: paymentItem.payment_item,
      amount: amountToUse
    }, req);

    res.json({
      success: true,
      data: {
        orderId,
        rrr: rrrResult.rrr,
        payerName,
        payerEmail,
        amount: amountToUse,
        payment_item: paymentItem.payment_item,
        paymentUrl // Send payment URL for redirect
      }
    });

  } catch (error) {
    console.error('Payment initiation error:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to initiate payment'
    });
  }
};

// Handle payment callback from Remita
export const handlePaymentCallback = async (req, res) => {
  try {
    const { rrr, orderId, status } = req.body;

    if (!rrr && !orderId) {
      return res.status(400).json({
        success: false,
        message: 'RRR or Order ID is required'
      });
    }

    // Get transaction
    let transaction;
    if (orderId) {
      transaction = await Transaction.getByOrderId(orderId);
    } else {
      transaction = await Transaction.getByRRR(rrr);
    }

    if (!transaction) {
      return res.status(404).json({
        success: false,
        message: 'Transaction not found'
      });
    }

    // If RRR is provided and transaction doesn't have one yet, update it
    if (rrr && !transaction.rrr) {
      await Transaction.updateRRR(transaction.order_id, rrr);
      transaction.rrr = rrr;
    }

    if (!transaction.rrr) {
      return res.status(202).json({
        success: true,
        data: {
          orderId: transaction.order_id,
          status: 'pending',
          message: 'Payment reference not yet available. Please retry shortly.'
        }
      });
    }

    const verification = await verifyTransactionWithRetry(
      transaction,
      {
        maxAttempts: 3,
        delayMs: 5000,
        context: 'payment_callback'
      }
    );
    const { updatedTransaction, nextStatus } = await applyVerificationResult(
      transaction,
      verification,
      req,
      'payment_verification'
    );

    console.log(`🔁 Verification result for ${transaction.order_id}: ${nextStatus}`);

    res.json({
      success: true,
      data: {
        orderId: updatedTransaction.order_id,
        rrr: updatedTransaction.rrr,
        status: updatedTransaction.status,
        message: verification.message,
        remitaStatus: verification.statuscode || verification.status,
        verification
      }
    });

  } catch (error) {
    console.error('Payment callback error:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to process payment callback'
    });
  }
};

// Get transaction by RRR (for receipt reprinting)
export const getTransactionByRRR = async (req, res) => {
  try {
    const { rrr } = req.params;

    const transaction = await Transaction.getByRRR(rrr);
    if (!transaction) {
      return res.status(404).json({
        success: false,
        message: 'Transaction not found'
      });
    }

    res.json({
      success: true,
      data: transaction
    });

  } catch (error) {
    console.error('Error fetching transaction:', error);
    res.status(500).json({
      success: false,
      message: 'Failed to fetch transaction'
    });
  }
};

// Requery payment by email and RRR
export const requeryPayment = async (req, res) => {
  try {
    const { email, rrr } = req.body;

    if (!email || !rrr) {
      return res.status(400).json({
        success: false,
        message: 'Email and RRR are required'
      });
    }

    // First check if transaction exists in our database
    let transaction = await Transaction.getByRRR(rrr);
    
    if (!transaction) {
      return res.status(404).json({
        success: false,
        message: 'Transaction not found. Please check your email and RRR.'
      });
    }

    // Transaction exists, verify email matches
    if (transaction.payer_email !== email) {
      return res.status(400).json({
        success: false,
        message: 'Email does not match transaction record'
      });
    }

    if (!transaction.rrr) {
      return res.status(202).json({
        success: true,
        data: {
          message: 'Payment reference not yet available. Please retry later.',
          transaction
        }
      });
    }

    const verification = await verifyTransactionWithRetry(
      transaction,
      {
        maxAttempts: 4,
        delayMs: 4000,
        context: 'payment_requery'
      }
    );
    const { updatedTransaction, nextStatus } = await applyVerificationResult(
      transaction,
      verification,
      req,
      'payment_requery'
    );

    const responseMessage = nextStatus === 'completed'
      ? 'Payment confirmed successfully'
      : nextStatus === 'pending'
        ? 'Payment is still pending confirmation'
        : 'Payment could not be confirmed';

    res.json({
      success: true,
      data: {
        message: responseMessage,
        transaction: updatedTransaction,
        status: nextStatus,
        verification
      }
    });

  } catch (error) {
    console.error('Requery error:', error);
    res.status(500).json({
      success: false,
      message: 'Failed to requery payment'
    });
  }
};

// Get all transactions (admin only)
export const getAllTransactions = async (req, res) => {
  try {
    const page = parseInt(req.query.page) || 1;
    const limit = parseInt(req.query.limit) || 50;
    const filters = {
      status: req.query.status,
      payment_item_id: req.query.payment_item_id,
      date_from: req.query.date_from,
      date_to: req.query.date_to
    };

    const transactions = await Transaction.getAll(page, limit, filters);
    const statistics = await Transaction.getStatistics(filters);

    res.json({
      success: true,
      data: {
        transactions,
        pagination: {
          page,
          limit,
          total: statistics.total_transactions
        },
        statistics
      }
    });

  } catch (error) {
    console.error('Error fetching transactions:', error);
    res.status(500).json({
      success: false,
      message: 'Failed to fetch transactions'
    });
  }
};
