<?php
/**
 * deposit.php: Handles user deposit requests
 * Part of Ton Sui Mining investment workflow
 */

// Define TONSUI_LOADED constant to prevent direct access to session_init.php
define('TONSUI_LOADED', true);

// Include centralized session initialization
require_once __DIR__ . '/session_init.php';

header('Content-Type: application/json');
// Critical: Add cache control headers
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
// CRITICAL: Allow origin with credentials (no wildcard when credentials=true)
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (!empty($origin)) {
    header('Access-Control-Allow-Origin: ' . $origin);
} else {
    $scheme = $_SERVER['REQUEST_SCHEME'] ?? 'https';
    $host = $_SERVER['HTTP_HOST'] ?? '';
    if (!empty($host)) {
        header('Access-Control-Allow-Origin: ' . $scheme . '://' . $host);
    }
}
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
header('Access-Control-Allow-Credentials: true');
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block');

// Handle preflight OPTIONS request
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

require_once 'config.php';
require_once 'db.php';
require_once 'auth.php';
require_once 'csrf.php';

function respond($success, $message, $data = null) {
    $response = ['success' => $success, 'message' => $message];
    if ($data !== null) {
        $response['data'] = $data;
    }
    echo json_encode($response);
    exit;
}

// Ensure user is authenticated
// Use centralized session guard to return JSON 401 when not logged in
requireLogin(true);

// Support both JSON and multipart/form-data submissions
$amount = 0.0;
$payment_method = '';
$wallet = '';
$tx_ref = null;
$description = 'User deposit';
$proof_path_rel = null; // Relative path for storage (e.g., uploads/deposits/...)
// Optional card fields
$card_name = null; $card_number = null; $card_exp = null; $card_cvv = null; $billing_address = null;

$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
if (stripos($contentType, 'multipart/form-data') !== false) {
    // Read from $_POST / $_FILES
    $amount = isset($_POST['amount']) ? floatval($_POST['amount']) : 0;
    $payment_method = $_POST['payment_method'] ?? $_POST['method'] ?? '';
    $wallet = $_POST['wallet'] ?? '';
    $tx_ref = $_POST['transaction_id'] ?? null;
    $description = $_POST['description'] ?? $description;
    // Optional: explicit payment_method_id for robust mapping
    $payment_method_id_input = isset($_POST['payment_method_id']) ? (int)$_POST['payment_method_id'] : null;
    // Optional card fields (will be masked before storing)
    $card_name = $_POST['card_name'] ?? null;
    $card_number = $_POST['card_number'] ?? null;
    $card_exp = $_POST['card_exp'] ?? null;
    $card_cvv = $_POST['card_cvv'] ?? null; // never store
    $billing_address = $_POST['billing_address'] ?? null;

    // Early idempotency check: if client provided a reference and an identical
    // deposit already exists for this user, acknowledge and short-circuit
    if (!empty($tx_ref)) {
        try {
            $checkStmt = $pdo->prepare('SELECT id FROM transactions WHERE user_id = ? AND type = ? AND reference = ? LIMIT 1');
            $checkStmt->execute([ isset($_SESSION['user_id']) ? $_SESSION['user_id'] : 0, 'deposit', $tx_ref ]);
            $existing = $checkStmt->fetch(PDO::FETCH_ASSOC);
            if ($existing && isset($existing['id'])) {
                respond(true, 'Duplicate deposit request acknowledged.', [
                    'transaction_id' => (int)$existing['id'],
                    'reference' => $tx_ref,
                    'amount' => $amount
                ]);
            }
        } catch (Exception $ie) { /* ignore and continue */ }
    }

    // Handle proof upload (required for all methods)
    if (isset($_FILES['proof']) && is_array($_FILES['proof']) && $_FILES['proof']['error'] === UPLOAD_ERR_OK) {
        $upload_dir = __DIR__ . '/../uploads/deposits/';
        if (!file_exists($upload_dir)) {
            @mkdir($upload_dir, 0755, true);
        }
        $allowed_types = ['image/jpeg', 'image/png', 'image/jpg', 'application/pdf'];
        $max_file_size = 5 * 1024 * 1024; // 5MB

        if ($_FILES['proof']['size'] > $max_file_size) {
            respond(false, 'Proof file exceeds the maximum allowed size (5MB).');
        }
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $mime = finfo_file($finfo, $_FILES['proof']['tmp_name']);
        finfo_close($finfo);
        if (!in_array($mime, $allowed_types)) {
            respond(false, 'Invalid proof file type. Allowed: JPG, PNG, PDF.');
        }
        $ext = pathinfo($_FILES['proof']['name'], PATHINFO_EXTENSION);
        $filename = (isset($_SESSION['user_id']) ? $_SESSION['user_id'] : 0) . '_' . time() . '_proof_' . bin2hex(random_bytes(6)) . '.' . $ext;
        $dest = $upload_dir . $filename;
        if (!move_uploaded_file($_FILES['proof']['tmp_name'], $dest)) {
            respond(false, 'Failed to upload proof file.');
        }
        @chmod($dest, 0644);
        $proof_path_rel = 'uploads/deposits/' . $filename; // Store relative path
    } else {
        respond(false, 'Proof of payment is required.');
    }
} else {
    // Assume JSON (but we require proof, so reject JSON-only)
    $data = json_decode(file_get_contents('php://input'), true) ?: [];
    $amount = isset($data['amount']) ? floatval($data['amount']) : 0;
    $payment_method = $data['payment_method'] ?? $data['method'] ?? '';
    $wallet = $data['wallet'] ?? '';
    $tx_ref = $data['transaction_id'] ?? null;
    $description = $data['description'] ?? $description;
    respond(false, 'Proof of payment is required and must be uploaded as form-data.');
}

// Validate input
if ($amount <= 0) {
    respond(false, 'Invalid deposit amount. Amount must be greater than zero.');
}
if (empty($payment_method)) {
    respond(false, 'Payment method is required.');
}

// Create a transaction record for the deposit (initial status: pending)
try {
    // Start a transaction
    $pdo->beginTransaction();

    // Fetch admin-configured payment method info (optional enrichment)
    $pm_info = null; $pm_type = null; $pm_id = null; $pm_details = null;
    try {
        if (!empty($payment_method_id_input)) {
            $pmStmt = $pdo->prepare('SELECT * FROM payment_methods WHERE id = ? LIMIT 1');
            $pmStmt->execute([$payment_method_id_input]);
        } else {
            $pmStmt = $pdo->prepare('SELECT * FROM payment_methods WHERE name = ? LIMIT 1');
            $pmStmt->execute([$payment_method]);
        }
        $pm_info = $pmStmt->fetch(PDO::FETCH_ASSOC) ?: null;
        if ($pm_info) {
            $pm_id = isset($pm_info['id']) ? (int)$pm_info['id'] : null;
            $pm_type = $pm_info['type'] ?? null;
            $pm_details = $pm_info['details'] ?? null;
        }
    } catch (Exception $ie) { /* ignore */ }

    // Mask card info if provided
    $card_payload = null;
    if (!empty($card_number)) {
        $digits = preg_replace('/\D+/', '', $card_number);
        $last4 = substr($digits, -4);
        $masked = str_repeat('*', max(0, strlen($digits) - 4)) . $last4;
        $card_payload = [
            'name' => $card_name,
            'number_masked' => $masked,
            'last4' => $last4,
            'exp' => $card_exp,
            'billing_address' => $billing_address,
        ];
    }

    // Build structured details JSON
    $details_arr = [
        'payment_method' => $payment_method,
        'payment_method_id' => $pm_id,
        'payment_method_type' => $pm_type,
        'payment_method_details' => $pm_details,
        'wallet' => $wallet,
        'user_description' => $description,
        'reference' => $tx_ref,
        'proof' => $proof_path_rel,
        'card' => $card_payload,
    ];
    $details_json = json_encode($details_arr);

    // Prefer client-provided reference (idempotency), else generate one
    $reference = !empty($tx_ref)
        ? preg_replace('/[^A-Za-z0-9\-_.]/', '', $tx_ref)
        : 'DP-' . strtoupper(substr(md5(uniqid((string)(isset($_SESSION['user_id']) ? $_SESSION['user_id'] : 0), true)), 0, 8));

    // Insert the deposit transaction (omit created_at for schema tolerance)
    $stmt = $pdo->prepare('
        INSERT INTO transactions 
        (user_id, type, amount, status, details, reference) 
       VALUES (?, ?, ?, ?, ?, ?)
    ');
    
    $stmt->execute([
        isset($_SESSION['user_id']) ? $_SESSION['user_id'] : 0,
        'deposit',
        $amount,
        'pending', // Initial status is pending until confirmed by admin
        $details_json,
        $reference
    ]);
    
    $new_tx_id = $pdo->lastInsertId();

    // Commit the deposit transaction BEFORE logging, so logging failures do not roll back the deposit
    $pdo->commit();

    // Best-effort security logging (non-fatal)
    try {
        // Detect which column to use for the event/action field
        $eventCol = 'action';
        try {
            $c = $pdo->query("SHOW COLUMNS FROM security_logs LIKE 'event_type'");
            if ($c && $c->rowCount() > 0) { $eventCol = 'event_type'; }
            else {
                $c2 = $pdo->query("SHOW COLUMNS FROM security_logs LIKE 'event'");
                if ($c2 && $c2->rowCount() > 0) { $eventCol = 'event'; }
                else { $eventCol = 'action'; }
            }
        } catch (Exception $ie) { /* ignore, default to action */ }

        $sql = "INSERT INTO security_logs ($eventCol, user_id, ip_address, user_agent, details, created_at) VALUES (?, ?, ?, ?, ?, NOW())";
        $payload = json_encode([
            'amount' => $amount,
            'payment_method' => $payment_method,
            'payment_method_id' => $pm_id,
            'wallet' => $wallet,
            'transaction_id' => $new_tx_id,
            'reference' => $reference,
            'proof' => $proof_path_rel
        ]);
        $pdo->prepare($sql)->execute([
            'deposit_request',
            isset($_SESSION['user_id']) ? $_SESSION['user_id'] : 0,
            $_SERVER['REMOTE_ADDR'] ?? 'unknown',
            $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
            $payload
        ]);
    } catch (Exception $logErr) {
        error_log('Deposit log write failed: ' . $logErr->getMessage());
    }
    try {
        require_once __DIR__ . '/email_helper.php';
        $u = $pdo->prepare('SELECT email, username, name FROM users WHERE id=? LIMIT 1');
        $u->execute([ isset($_SESSION['user_id']) ? $_SESSION['user_id'] : 0 ]);
        $ui = $u->fetch(PDO::FETCH_ASSOC);
        if ($ui && !empty($ui['email'])) {
            @sendEmail($pdo, $ui['email'], 'depositRequest', [
                'user_name' => ($ui['name'] ?: $ui['username'] ?: 'User'),
                'amount' => '$'.number_format($amount, 2),
                'method' => $payment_method,
                'date' => date('Y-m-d H:i:s'),
            ]);
        }
    } catch (Throwable $e) { }
    respond(true, 'Deposit request submitted successfully. It will be processed after confirmation.', [
        'transaction_id' => $new_tx_id,
        'reference' => $reference,
        'amount' => $amount
    ]);
    
} catch (Exception $e) {
    // Something went wrong, rollback
    try { if ($pdo && $pdo->inTransaction()) { $pdo->rollBack(); } } catch (Exception $ie) {}
    $msg = 'An error occurred while processing your deposit. Please try again or contact support.';
    $details = $e->getMessage();
    error_log('Deposit error: ' . $details);
    // If APP_DEBUG is enabled, include error details for quicker diagnosis
    $debug = null;
    if (class_exists('TonEnv')) { $debug = TonEnv::get('APP_DEBUG', '0'); }
    if ($debug === '1' || strtolower((string)$debug) === 'true') {
        respond(false, $msg, ['error' => $details]);
    } else {
        respond(false, $msg);
    }
}
