<?php
/**
 * Sub-Agent Top-up API
 * Handles top-up requests from sub-agents and redirects to Paystack using store owner's credentials
 * SECURITY: Multiple layers of protection including CSRF, rate limiting, amount validation, and URL manipulation prevention
 */

session_start();
require_once '../config.php';
require_once '../app/classes/StoreManager.php';
require_once '../app/classes/MinimumTopupManager.php';
require_once '../app/classes/PaystackChargeManager.php';
require_once '../app/classes/SessionManager.php';
use App\classes\SessionManager;

header('Content-Type: application/json');

// SECURITY: Rate limiting - prevent abuse
function checkRateLimit($conn, $userId, $maxAttempts = 5, $timeWindow = 300) {
    $stmt = $conn->prepare("
        SELECT COUNT(*) as attempt_count 
        FROM orders_payments 
        WHERE user_id = ? 
        AND payment_method = 'paystack' 
        AND payment_status = 'pending'
        AND created_at > DATE_SUB(NOW(), INTERVAL ? SECOND)
    ");
    $stmt->bind_param("ii", $userId, $timeWindow);
    $stmt->execute();
    $result = $stmt->get_result();
    $data = $result->fetch_assoc();
    $stmt->close();
    
    return $data['attempt_count'] < $maxAttempts;
}

// Check if user is logged in
if (!isset($_SESSION['user_id'])) {
    http_response_code(401);
    echo json_encode(['success' => false, 'message' => 'Unauthorized']);
    exit;
}

$userId = $_SESSION['user_id'];
$userIp = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';

// SECURITY: Validate session
$sessionManager = new SessionManager($conn);
$sessionValidation = $sessionManager->validateSession($userId);

if (!$sessionValidation['valid']) {
    error_log("SECURITY: Invalid session detected - User ID: $userId, IP: $userIp, Reason: " . $sessionValidation['reason']);
    $sessionManager->forceLogout();
    http_response_code(401);
    echo json_encode(['success' => false, 'message' => 'Session expired. Please login again.']);
    exit;
}

// MULTI-LAYER SECURITY CHECK: Verify user is actually a sub-agent
$storeManager = new StoreManager($conn);
$verification = $storeManager->verifyAgent($userId);

// If user is not a legitimate sub-agent, deny access
if (!$verification['valid']) {
    error_log("SECURITY: Sub-Agent Top-up API Access Denied - User ID: $userId, IP: $userIp, Reason: " . $verification['reason']);
    http_response_code(403);
    echo json_encode(['success' => false, 'message' => 'Access denied. Only sub-agents can top up their account.']);
    exit;
}

// Validate request method
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(['success' => false, 'message' => 'Invalid request method']);
    exit;
}

// SECURITY: Rate limiting check
if (!checkRateLimit($conn, $userId, 5, 300)) {
    error_log("SECURITY: Rate limit exceeded - User ID: $userId, IP: $userIp");
    http_response_code(429);
    echo json_encode(['success' => false, 'message' => 'Too many requests. Please wait a few minutes before trying again.']);
    exit;
}

// Get and validate input
$input = json_decode(file_get_contents('php://input'), true);

if (!is_array($input)) {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => 'Invalid request data']);
    exit;
}

// SECURITY: CSRF token validation (optional but recommended)
if (isset($input['csrf_token'])) {
    if (!isset($_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $input['csrf_token'])) {
        error_log("SECURITY: Invalid CSRF token - User ID: $userId, IP: $userIp");
        http_response_code(403);
        echo json_encode(['success' => false, 'message' => 'Invalid security token. Please refresh the page and try again.']);
        exit;
    }
}

$amount = isset($input['amount']) ? floatval($input['amount']) : 0;

// SECURITY: Strict amount validation
if ($amount <= 0) {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => 'Invalid amount. Amount must be greater than zero.']);
    exit;
}

// SECURITY: Maximum amount limit (prevent excessive top-ups)
$maxAmount = 1500; // GH₵ 1,500 maximum
if ($amount > $maxAmount) {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => "Maximum top-up amount is GH₵ " . number_format($maxAmount, 2)]);
    exit;
}

// SECURITY: Validate amount precision (max 2 decimal places)
if (round($amount, 2) != $amount) {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => 'Invalid amount precision. Maximum 2 decimal places allowed.']);
    exit;
}

// Get user email, store_id and verify user exists
$userStmt = $conn->prepare("SELECT email, balance, role, is_store_owner, store_id FROM agents WHERE id = ?");
$userStmt->bind_param("i", $userId);
$userStmt->execute();
$userResult = $userStmt->get_result();
$user = $userResult->fetch_assoc();
$userStmt->close();

if (!$user || empty($user['email'])) {
    error_log("SECURITY: User not found for top-up - User ID: $userId, IP: $userIp");
    http_response_code(404);
    echo json_encode(['success' => false, 'message' => 'User email not found. Please contact support.']);
    exit;
}

// SECURITY: Double-check sub-agent status from database
if ($user['role'] === 'store_owner' || $user['is_store_owner'] == 1 || empty($user['store_id'])) {
    error_log("SECURITY: Unauthorized top-up attempt - User ID: $userId, Role: " . $user['role'] . ", Store ID: " . ($user['store_id'] ?? 'null') . ", IP: $userIp");
    http_response_code(403);
    echo json_encode(['success' => false, 'message' => 'Access denied. Only sub-agents can top up their account.']);
    exit;
}

// SECURITY: Check for recent pending top-ups to prevent duplicate attempts
$checkPendingStmt = $conn->prepare("
    SELECT id, payment_reference, created_at 
    FROM subagent_topup_tracking 
    WHERE user_id = ? 
    AND payment_status = 'pending' 
    AND created_at > DATE_SUB(NOW(), INTERVAL 5 MINUTE)
    ORDER BY created_at DESC
    LIMIT 1
");
$checkPendingStmt->bind_param("i", $userId);
$checkPendingStmt->execute();
$pendingResult = $checkPendingStmt->get_result();
$pendingTopup = $pendingResult->fetch_assoc();
$checkPendingStmt->close();

if ($pendingTopup) {
    $timeSince = time() - strtotime($pendingTopup['created_at']);
    $minutesAgo = floor($timeSince / 60);
    error_log("SECURITY: Duplicate top-up attempt prevented - User ID: $userId, Previous Reference: {$pendingTopup['payment_reference']}, Created: {$minutesAgo} minutes ago, IP: $userIp");
    http_response_code(429);
    echo json_encode([
        'success' => false, 
        'message' => "You have a pending top-up request. Please complete or cancel the previous request (Reference: {$pendingTopup['payment_reference']}) before starting a new one. If you need help, please contact support."
    ]);
    exit;
}

$userEmail = $user['email'];
$storeId = $user['store_id'];

// Get store owner's Paystack credentials
$paystackStmt = $conn->prepare("SELECT public_key, secret_key, is_active FROM store_paystack_credentials WHERE store_id = ? AND is_active = 1");
$paystackStmt->bind_param("i", $storeId);
$paystackStmt->execute();
$paystackResult = $paystackStmt->get_result();
$paystackCreds = $paystackResult->fetch_assoc();
$paystackStmt->close();

if (!$paystackCreds || empty($paystackCreds['public_key']) || empty($paystackCreds['secret_key'])) {
    error_log("SECURITY: Store Paystack credentials not configured - Store ID: $storeId, User ID: $userId, IP: $userIp");
    http_response_code(500);
    echo json_encode(['success' => false, 'message' => 'Payment service not configured for this store. Please contact the store owner.']);
    exit;
}

// Validate minimum top-up amount
$minimumTopupManager = new MinimumTopupManager($conn);
$validation = $minimumTopupManager->validateTopupAmount($amount);
if (!$validation['valid']) {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => $validation['message']]);
    exit;
}

// Calculate charge (server-side calculation - cannot be manipulated)
$chargeManager = new PaystackChargeManager($conn);
$chargeCalculation = $chargeManager->calculateChargedAmount($amount);

$baseAmount = $chargeCalculation['base_amount'];
$chargeAmount = $chargeCalculation['charge_amount'];
$totalAmount = $chargeCalculation['total_amount'];
$chargeType = $chargeCalculation['charge_type'];

// SECURITY: Verify charge calculation is reasonable
if ($totalAmount <= 0 || $totalAmount < $baseAmount) {
    error_log("SECURITY: Invalid charge calculation - User ID: $userId, Amount: $amount, Total: $totalAmount, IP: $userIp");
    http_response_code(500);
    echo json_encode(['success' => false, 'message' => 'Payment calculation error. Please try again.']);
    exit;
}

// Generate unique payment reference
function generatePaymentReference($conn) {
    $maxAttempts = 100;
    $attempts = 0;
    
    do {
        $reference = 'SUBAGENT_' . time() . '_' . bin2hex(random_bytes(4));
        
        // Validate reference is not empty
        if (empty($reference)) {
            throw new Exception("Failed to generate payment reference: empty reference");
        }
        
        // Check if reference already exists in BOTH tables
        $checkStmt = $conn->prepare("
            SELECT id FROM orders_payments WHERE payment_reference = ?
            UNION
            SELECT id FROM subagent_topup_tracking WHERE payment_reference = ?
        ");
        $checkStmt->bind_param("ss", $reference, $reference);
        $checkStmt->execute();
        $result = $checkStmt->get_result();
        $exists = $result->num_rows > 0;
        $checkStmt->close();
        
        $attempts++;
        
        if (!$exists) {
            return $reference;
        }
    } while ($attempts < $maxAttempts);
    
    throw new Exception("Failed to generate unique payment reference after $maxAttempts attempts");
}

// SECURITY: Generate HMAC signature for payment parameters to prevent URL manipulation
function generatePaymentSignature($reference, $amount, $email, $baseAmount, $chargeAmount, $secretKey) {
    $data = $reference . '|' . $amount . '|' . $email . '|' . $baseAmount . '|' . $chargeAmount;
    return hash_hmac('sha256', $data, $secretKey);
}

try {
    $conn->begin_transaction();
    
    // Generate unique payment reference
    $reference = generatePaymentReference($conn);
    
    // SECURITY: Validate reference is not empty
    if (empty($reference) || !is_string($reference) || strlen($reference) < 10) {
        throw new Exception("Invalid payment reference generated");
    }
    
    // Convert total amount to pesewas (minor units) for Paystack
    $amountKobo = intval(round($totalAmount * 100));
    
    // SECURITY: Verify amount conversion is correct
    if ($amountKobo < 100) {
        throw new Exception("Amount too small. Minimum is 1.00 GHS");
    }
    
    // SECURITY: Get store owner ID for tracking
    $storeOwnerStmt = $conn->prepare("SELECT owner_id FROM stores WHERE id = ?");
    $storeOwnerStmt->bind_param("i", $storeId);
    $storeOwnerStmt->execute();
    $storeOwnerResult = $storeOwnerStmt->get_result();
    $storeOwnerData = $storeOwnerResult->fetch_assoc();
    $storeOwnerStmt->close();
    
    if (!$storeOwnerData) {
        throw new Exception("Store not found");
    }
    
    $storeOwnerId = $storeOwnerData['owner_id'];
    
    // SECURITY: Track sub-agent top-up BEFORE creating payment intent
    // This creates an audit trail and allows verification on callback
    $insertTrackingStmt = $conn->prepare("
        INSERT INTO subagent_topup_tracking 
        (user_id, store_id, store_owner_id, payment_reference, base_amount, charge_amount, 
         total_amount, payment_status, payment_method, ip_address, user_agent, created_at) 
        VALUES (?, ?, ?, ?, ?, ?, ?, 'pending', 'paystack', ?, ?, NOW())
    ");
    
    if (!$insertTrackingStmt) {
        throw new Exception("Database error: Failed to prepare top-up tracking insert");
    }
    
    $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
    
    // SECURITY: Validate reference before binding
    if (empty($reference) || !is_string($reference)) {
        throw new Exception("Invalid payment reference: must be a non-empty string");
    }
    
    $insertTrackingStmt->bind_param("iiisddsss",  // Fixed: payment_reference is 's' (string), not 'i' (int) 
        $userId, 
        $storeId, 
        $storeOwnerId, 
        $reference,  // Changed from 'i' (int) to 's' (string)
        $baseAmount, 
        $chargeAmount, 
        $totalAmount, 
        $userIp, 
        $userAgent
    );
    
    if (!$insertTrackingStmt->execute()) {
        $errorCode = $conn->errno;
        $errorMsg = $conn->error;
        $insertTrackingStmt->close();
        
        if ($errorCode == 1062) { // Duplicate entry
            throw new Exception("Payment reference already exists. Please try again.");
        } else {
            error_log("SECURITY: Failed to store sub-agent top-up tracking - User ID: $userId, Error: $errorMsg, IP: $userIp");
            throw new Exception("Failed to initialize payment. Please try again.");
        }
    }
    
    $trackingId = $conn->insert_id;
    $insertTrackingStmt->close();
    
    // SECURITY: Store payment intent in database BEFORE redirecting (prevents manipulation)
    // This creates an audit trail and allows verification on callback
    $insertIntentStmt = $conn->prepare("
        INSERT INTO orders_payments 
        (user_id, total_amount, payment_method, payment_status, payment_reference, 
         payment_type, payment_date, created_at) 
        VALUES (?, ?, 'paystack', 'pending', ?, 'topup', NOW(), NOW())
    ");
    
    if (!$insertIntentStmt) {
        throw new Exception("Database error: Failed to prepare payment intent insert");
    }
    
    $insertIntentStmt->bind_param("ids", $userId, $baseAmount, $reference);
    
    if (!$insertIntentStmt->execute()) {
        $errorCode = $conn->errno;
        $errorMsg = $conn->error;
        $insertIntentStmt->close();
        
        if ($errorCode == 1062) { // Duplicate entry
            throw new Exception("Payment reference already exists. Please try again.");
        } else {
            error_log("SECURITY: Failed to store payment intent - User ID: $userId, Error: $errorMsg, IP: $userIp");
            throw new Exception("Failed to initialize payment. Please try again.");
        }
    }
    
    $paymentIntentId = $conn->insert_id;
    $insertIntentStmt->close();
    
    // SECURITY: Use store owner's Paystack secret key
    $paystackSecretKey = $paystackCreds['secret_key'];
    
    // SECURITY: Generate HMAC signature to prevent URL manipulation
    $signature = generatePaymentSignature($reference, $amountKobo, $userEmail, $baseAmount, $chargeAmount, $paystackSecretKey);
    
    // SECURITY: Store signature in session for verification
    $_SESSION['topup_signature_' . $reference] = [
        'signature' => $signature,
        'reference' => $reference,
        'amount' => $amountKobo,
        'base_amount' => $baseAmount,
        'charge_amount' => $chargeAmount,
        'user_id' => $userId,
        'store_id' => $storeId,
        'timestamp' => time()
    ];
    
    // Commit transaction
    $conn->commit();
    
    // Build redirect URL to paystack_redirect.php
    $baseUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'];
    $basePath = rtrim(str_replace('\\', '/', dirname(dirname($_SERVER['PHP_SELF']))), '/');
    
    // SECURITY: Include signature in URL for verification
    $redirectUrl = $baseUrl . $basePath . '/paystack_redirect.php?' . http_build_query([
        'ref' => $reference,
        'amount' => $amountKobo,
        'email' => $userEmail,
        'base_amount' => $baseAmount,
        'charge_amount' => $chargeAmount,
        'charge_type' => $chargeType,
        'sig' => $signature,
        'store_id' => $storeId  // Pass store_id to use store owner's Paystack credentials
    ]);
    
    // SECURITY: Log payment intent creation
    error_log("SECURITY: Sub-Agent Top-up Tracking Created - Tracking ID: $trackingId, User ID: $userId, Store ID: $storeId, Store Owner ID: $storeOwnerId, Reference: $reference, Amount: GH₵ $baseAmount, IP: $userIp");
    
    echo json_encode([
        'success' => true,
        'redirect_url' => $redirectUrl,
        'reference' => $reference
    ]);
    
} catch (Exception $e) {
    // Rollback transaction if it was started
    try {
        $conn->rollback();
    } catch (Exception $rollbackException) {
        // Ignore rollback errors
    }
    error_log("SECURITY: Sub-Agent Top-up Error - User ID: $userId, Error: " . $e->getMessage() . ", IP: $userIp");
    http_response_code(500);
    echo json_encode([
        'success' => false,
        'message' => 'Failed to initialize payment: ' . $e->getMessage()
    ]);
}
?>

