<?php
/**
 * Manual Paystack Payment Verification
 * Allows users to manually verify and get credited for Paystack payments
 * Prevents duplicate processing using idempotency checks
 */

session_start();
require_once 'config.php';
require_once 'config_paystack.php';
require_once 'app/classes/BalanceHistory.php';
require_once 'app/classes/NotificationManager.php';
require_once 'app/classes/AdminNotificationManager.php';
use App\classes\BalanceHistory;

header('Content-Type: application/json; charset=utf-8');

// Check if user is logged in
if (!isset($_SESSION['user_id'])) {
    echo json_encode([
        'success' => false,
        'message' => 'You must be logged in to verify payments.'
    ]);
    exit;
}

$user_id = $_SESSION['user_id'];
$reference = isset($_POST['reference']) ? trim($_POST['reference']) : '';

if (empty($reference)) {
    echo json_encode([
        'success' => false,
        'message' => 'Payment reference is required.'
    ]);
    exit;
}

// Validate reference format (Paystack references are typically alphanumeric)
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $reference)) {
    echo json_encode([
        'success' => false,
        'message' => 'Invalid payment reference format.'
    ]);
    exit;
}

// Get user information
$stmt = $conn->prepare("SELECT id, username, email, balance, role FROM agents WHERE id = ?");
$stmt->bind_param("i", $user_id);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();
$stmt->close();

if (!$user) {
    echo json_encode([
        'success' => false,
        'message' => 'User not found.'
    ]);
    exit;
}

$user_email = strtolower(trim($user['email']));

// Verify transaction with Paystack
$verify = paystackVerifyTransaction($reference);
$ok = $verify['success'] && (($verify['data']['data']['status'] ?? '') === 'success');

if (!$ok) {
    $errorMsg = $verify['error'] ?? 'Payment verification failed';
    $status = $verify['data']['data']['status'] ?? 'unknown';
    
    echo json_encode([
        'success' => false,
        'message' => 'Payment verification failed. ' . ($status !== 'unknown' ? "Status: $status" : $errorMsg)
    ]);
    exit;
}

$paymentData = $verify['data']['data'] ?? [];
$customerEmail = strtolower(trim($paymentData['customer']['email'] ?? ''));
$amountPaid = intval($paymentData['amount'] ?? 0); // in pesewas
$totalAmountGHS = $amountPaid / 100; // convert to GHS
$externalTxnId = $paymentData['id'] ?? null;

// Verify that the payment belongs to the logged-in user
if ($customerEmail !== $user_email) {
    echo json_encode([
        'success' => false,
        'message' => 'This payment reference does not belong to your account. Please use the reference from your payment email.'
    ]);
    exit;
}

// Get the base amount from metadata (excluding charge)
$metadata = $paymentData['metadata'] ?? [];
$baseAmount = floatval($metadata['base_amount'] ?? 0);
$chargeAmount = floatval($metadata['charge_amount'] ?? 0);

// Fallback to full amount if base amount is not available (backward compatibility)
$amountGHS = ($baseAmount > 0) ? $baseAmount : $totalAmountGHS;

if ($amountGHS <= 0) {
    echo json_encode([
        'success' => false,
        'message' => 'Invalid payment amount.'
    ]);
    exit;
}

// Start database transaction
$conn->begin_transaction();

try {
    // CRITICAL: IDEMPOTENCY CHECK - Prevent duplicate processing
    $checkStmt = $conn->prepare("SELECT id, user_id, total_amount, payment_date FROM orders_payments WHERE payment_reference = ? LIMIT 1");
    if (!$checkStmt) {
        throw new Exception("Database error: Failed to prepare idempotency check");
    }
    $checkStmt->bind_param("s", $reference);
    $checkStmt->execute();
    $existingPayment = $checkStmt->get_result()->fetch_assoc();
    $checkStmt->close();
    
    if ($existingPayment) {
        // Payment already processed
        $conn->commit();
        
        $processedDate = $existingPayment['payment_date'] ?? 'Unknown';
        echo json_encode([
            'success' => false,
            'message' => 'This payment reference has already been processed.',
            'already_processed' => true,
            'processed_date' => $processedDate,
            'amount' => number_format($existingPayment['total_amount'], 2)
        ]);
        exit;
    }
    
    $userId = $user['id'];
    $currentBalance = floatval($user['balance']);
    
    // 1. INSERT PAYMENT RECORD FIRST (with UNIQUE constraint on payment_reference)
    $insertPayment = $conn->prepare("
        INSERT INTO orders_payments 
        (user_id, total_amount, payment_method, payment_status, payment_reference, 
         payment_type, external_transaction_id, raw_response_data, payment_date, created_at) 
        VALUES (?, ?, 'paystack', 'completed', ?, 'paystack', ?, ?, NOW(), NOW())
    ");
    if (!$insertPayment) {
        throw new Exception("Database error: Failed to prepare payment insert");
    }
    
    $rawData = json_encode($paymentData);
    $insertPayment->bind_param("idsss", $userId, $amountGHS, $reference, $externalTxnId, $rawData);
    
    if (!$insertPayment->execute()) {
        $errorCode = $conn->errno;
        $errorMsg = $conn->error;
        
        if ($errorCode == 1062) { // Duplicate entry error
            $conn->commit();
            echo json_encode([
                'success' => false,
                'message' => 'This payment reference has already been processed.',
                'already_processed' => true
            ]);
            exit;
        } else {
            throw new Exception("Failed to record payment - database error: $errorMsg");
        }
    }
    $insertPayment->close();
    
    // 1b. INSERT CHARGE AUDIT TRAIL (if charge was applied)
    if ($chargeAmount > 0) {
        try {
            $chargeType = $metadata['charge_type'] ?? 'unknown';
            $insertChargeAudit = $conn->prepare("
                INSERT INTO paystack_charge_audit 
                (order_reference, user_id, base_amount, charge_amount, total_amount, charge_type, created_at) 
                VALUES (?, ?, ?, ?, ?, ?, NOW())
            ");
            if ($insertChargeAudit) {
                $insertChargeAudit->bind_param("siddds", $reference, $userId, $baseAmount, $chargeAmount, $totalAmountGHS, $chargeType);
                $insertChargeAudit->execute();
                $insertChargeAudit->close();
            }
        } catch (Exception $auditError) {
            // Log but don't fail transaction
            error_log("Charge audit error for payment $reference: " . $auditError->getMessage());
        }
    }
    
    // 2. UPDATE USER BALANCE
    $updateStmt = $conn->prepare("UPDATE agents SET balance = balance + ? WHERE id = ?");
    if (!$updateStmt) {
        throw new Exception("Database error: Failed to prepare balance update");
    }
    $updateStmt->bind_param("di", $amountGHS, $userId);
    if (!$updateStmt->execute()) {
        $errorMsg = $updateStmt->error;
        $updateStmt->close();
        throw new Exception("Failed to update user balance: $errorMsg");
    }
    
    $affectedRows = $updateStmt->affected_rows;
    $updateStmt->close();
    
    if ($affectedRows === 0) {
        throw new Exception("Balance update failed - no rows affected");
    }
    
    // 3. LOG BALANCE CHANGE FOR AUDIT TRAIL
    BalanceHistory::log($conn, $userId, $amountGHS, 'topup', null, $reference);
    
    // 4. SEND NOTIFICATION (non-critical)
    try {
        $notificationManager = new NotificationManager($conn);
        $notificationData = [
            'amount' => number_format($amountGHS, 2),
            'balance' => number_format($currentBalance + $amountGHS, 2)
        ];
        $notificationManager->sendNotification($userId, 'balance_topup', $notificationData);
    } catch (Exception $notifError) {
        error_log("Notification error for payment $reference: " . $notifError->getMessage());
    }
    
    // Commit transaction
    $conn->commit();
    
    // Log successful payment processing
    error_log("SUCCESS: Manual Paystack payment verified - Ref: $reference, User: $userId, Amount: GHS $amountGHS");
    
    echo json_encode([
        'success' => true,
        'message' => 'Payment verified successfully! Your account has been credited.',
        'amount' => number_format($amountGHS, 2),
        'new_balance' => number_format($currentBalance + $amountGHS, 2),
        'reference' => $reference
    ]);
    
} catch (Exception $e) {
    $conn->rollback();
    error_log("ERROR: Manual payment verification failed - Ref: $reference, User: $userId, Error: " . $e->getMessage());
    
    echo json_encode([
        'success' => false,
        'message' => 'Payment verification failed: ' . $e->getMessage()
    ]);
}
?>



