<?php
/**
 * Store Owner Top-up API
 * Handles top-up requests from store owners and redirects to Paystack
 * 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 store owner
$storeManager = new StoreManager($conn);
$verification = $storeManager->verifyStoreOwner($userId);

// If user is not a legitimate store owner, deny access
if (!$verification['valid']) {
    error_log("SECURITY: Store 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 store owners 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 = 100; // GH₵ 100 maximum for Paystack
if ($amount > $maxAmount) {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => "For amounts above GH₵ " . number_format($maxAmount, 2) . ", please use Mobile Money."]);
    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 and verify user exists
$userStmt = $conn->prepare("SELECT email, balance, role, is_store_owner 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 store owner status from database
if ($user['role'] !== 'store_owner' || $user['is_store_owner'] != 1) {
    error_log("SECURITY: Unauthorized top-up attempt - User ID: $userId, Role: " . $user['role'] . ", IP: $userIp");
    http_response_code(403);
    echo json_encode(['success' => false, 'message' => 'Access denied. Only store owners can top up their account.']);
    exit;
}

$userEmail = $user['email'];

// 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) {
    $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    $maxAttempts = 100;
    $attempts = 0;
    
    do {
        $reference = 'STORE_' . time() . '_' . bin2hex(random_bytes(4));
        
        // Check if reference already exists
        $checkStmt = $conn->prepare("SELECT id FROM orders_payments WHERE payment_reference = ?");
        $checkStmt->bind_param("s", $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");
}

// 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);
    
    // 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: 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: Get Paystack secret key from database (admin-configured)
    require_once '../config_paystack.php';
    $paystackConfig = getPaystackConfig(true);
    $paystackSecretKey = $paystackConfig['secret_key'];
    
    if (empty($paystackSecretKey)) {
        error_log("SECURITY: Paystack secret key not configured - User ID: $userId, IP: $userIp");
        $conn->rollback();
        http_response_code(500);
        echo json_encode(['success' => false, 'message' => 'Payment service not configured. Please contact support.']);
        exit;
    }
    
    // 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,
        '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
    ]);
    
    // SECURITY: Log payment intent creation
    error_log("SECURITY: Payment intent created - User ID: $userId, Reference: $reference, Amount: GH₵ $baseAmount, IP: $userIp");
    
    echo json_encode([
        'success' => true,
        'redirect_url' => $redirectUrl,
        'reference' => $reference
    ]);
    
} catch (Exception $e) {
    if ($conn->in_transaction) {
        $conn->rollback();
    }
    error_log("SECURITY: Store Owner 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()
    ]);
}
?>
