<?php
/**
 * admin_edit_transaction.php
 *
 * Admin endpoint to edit an existing transaction's amount, date/time and description.
 *
 * Rules:
 * - Admin-only (requireAdmin)
 * - Supports POST with JSON body
 * - For COMPLETED deposits/withdrawals, adjusts the user's balance (and totals) by the delta
 * - For other types/statuses, only updates the transaction row (no balance change)
 */

// JSON + CORS headers
header('Content-Type: application/json');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
$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, Authorization');
header('Access-Control-Allow-Credentials: true');
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block');

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

// Guard and deps
if (!defined('TONSUI_LOADED')) {
    define('TONSUI_LOADED', true);
}
require_once __DIR__ . '/session_init.php';
require_once __DIR__ . '/auth.php';
require_once __DIR__ . '/config.php';
require_once __DIR__ . '/db.php';
requireAdmin(true);

function tx_edit_respond($success, $message, $extra = []) {
    $resp = ['success' => $success, 'message' => $message];
    if (!empty($extra)) {
        $resp['data'] = $extra;
    }
    echo json_encode($resp);
    exit;
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    tx_edit_respond(false, 'Method not allowed');
}

$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
if (!is_array($data)) {
    http_response_code(400);
    tx_edit_respond(false, 'Invalid JSON payload');
}

$transactionId = isset($data['transaction_id']) ? (int)$data['transaction_id'] : 0;
$newAmount = isset($data['amount']) ? (float)$data['amount'] : null;
$description = isset($data['description']) ? trim((string)$data['description']) : '';
$date = isset($data['date']) ? trim((string)$data['date']) : '';
$time = isset($data['time']) ? trim((string)$data['time']) : '';

if ($transactionId <= 0) {
    http_response_code(400);
    tx_edit_respond(false, 'Invalid transaction ID');
}

if ($newAmount === null || $newAmount <= 0) {
    http_response_code(400);
    tx_edit_respond(false, 'Amount must be greater than zero');
}

try {
    $pdo->beginTransaction();

    // Fetch transaction
    $stmt = $pdo->prepare('SELECT * FROM transactions WHERE id = ? LIMIT 1');
    $stmt->execute([$transactionId]);
    $tx = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$tx) {
        $pdo->rollBack();
        http_response_code(404);
        tx_edit_respond(false, 'Transaction not found');
    }

    $oldAmount = isset($tx['amount']) ? (float)$tx['amount'] : 0.0;
    $type = strtolower((string)($tx['type'] ?? ''));
    $status = strtolower((string)($tx['status'] ?? ''));
    $userId = isset($tx['user_id']) ? (int)$tx['user_id'] : 0;

    if ($userId <= 0) {
        $pdo->rollBack();
        http_response_code(400);
        tx_edit_respond(false, 'Transaction has invalid user reference');
    }

    $adjustBalance = false;
    $balanceDelta = 0.0;
    $totalDepositedDelta = 0.0;
    $totalWithdrawnDelta = 0.0;

    // Only adjust balance for COMPLETED deposit/withdrawal transactions
    if (in_array($type, ['deposit', 'withdrawal'], true) && $status === 'completed') {
        $adjustBalance = true;
    }

    // Introspect optional columns
    $hasTotalDeposited = false;
    $hasTotalWithdrawn = false;
    $hasCreatedAt = false;
    $hasUpdatedAt = false;
    $hasAdminNoteCol = false;

    try {
        $cols = $pdo->query("SHOW COLUMNS FROM users LIKE 'total_deposited'");
        $hasTotalDeposited = $cols && $cols->rowCount() > 0;
    } catch (Exception $e) { /* ignore */ }

    try {
        $cols = $pdo->query("SHOW COLUMNS FROM users LIKE 'total_withdrawn'");
        $hasTotalWithdrawn = $cols && $cols->rowCount() > 0;
    } catch (Exception $e) { /* ignore */ }

    try {
        $cols = $pdo->query("SHOW COLUMNS FROM transactions LIKE 'created_at'");
        $hasCreatedAt = $cols && $cols->rowCount() > 0;
    } catch (Exception $e) { /* ignore */ }

    try {
        $cols = $pdo->query("SHOW COLUMNS FROM transactions LIKE 'updated_at'");
        $hasUpdatedAt = $cols && $cols->rowCount() > 0;
    } catch (Exception $e) { /* ignore */ }

    try {
        $cols = $pdo->query("SHOW COLUMNS FROM transactions LIKE 'admin_note'");
        $hasAdminNoteCol = $cols && $cols->rowCount() > 0;
    } catch (Exception $e) { /* ignore */ }

    // Adjust user balance if needed
    if ($adjustBalance) {
        // Lock user row for update
        $selCols = 'balance';
        if ($hasTotalDeposited) { $selCols .= ', total_deposited'; }
        if ($hasTotalWithdrawn) { $selCols .= ', total_withdrawn'; }

        $uStmt = $pdo->prepare("SELECT $selCols FROM users WHERE id = ? FOR UPDATE");
        $uStmt->execute([$userId]);
        $user = $uStmt->fetch(PDO::FETCH_ASSOC);

        if (!$user) {
            $pdo->rollBack();
            http_response_code(404);
            tx_edit_respond(false, 'User not found for this transaction');
        }

        $currentBalance = isset($user['balance']) ? (float)$user['balance'] : 0.0;

        if ($type === 'deposit') {
            // Completed deposit: net effect is +amount on balance
            $balanceDelta = $newAmount - $oldAmount;
            $totalDepositedDelta = $newAmount - $oldAmount;
        } elseif ($type === 'withdrawal') {
            // Completed withdrawal: net effect is -amount; adjust balance accordingly
            // New net effect: -newAmount; current effect: -oldAmount; delta = old - new
            $balanceDelta = $oldAmount - $newAmount;
            $totalWithdrawnDelta = $newAmount - $oldAmount; // total withdrawn should follow the amount
        }

        $newBalance = $currentBalance + $balanceDelta;

        // Update users table
        $setParts = ['balance = balance + ?'];
        $params = [$balanceDelta];

        if ($hasTotalDeposited && $totalDepositedDelta != 0.0) {
            $setParts[] = 'total_deposited = COALESCE(total_deposited, 0) + ?';
            $params[] = $totalDepositedDelta;
        }
        if ($hasTotalWithdrawn && $totalWithdrawnDelta != 0.0) {
            $setParts[] = 'total_withdrawn = COALESCE(total_withdrawn, 0) + ?';
            $params[] = $totalWithdrawnDelta;
        }

        $setParts[] = 'updated_at = NOW()';
        $params[] = $userId;

        $updSql = 'UPDATE users SET ' . implode(', ', $setParts) . ' WHERE id = ?';
        $updStmt = $pdo->prepare($updSql);
        $updStmt->execute($params);
    }

    // Parse and update details JSON
    $detailsArr = [];
    if (!empty($tx['details'])) {
        $parsed = json_decode($tx['details'], true);
        if (is_array($parsed)) {
            $detailsArr = $parsed;
        }
    }

    if ($description !== '') {
        $detailsArr['admin_notes'] = $description;
    }

    $detailsArr['admin_edit'] = [
        'admin_id' => isset($_SESSION['admin_id']) ? (int)$_SESSION['admin_id'] : null,
        'edited_at' => date('Y-m-d H:i:s'),
        'old_amount' => $oldAmount,
        'new_amount' => $newAmount,
    ];

    $newDetailsJson = json_encode($detailsArr);

    // Build created_at value if provided
    $createdAtValue = null;
    if ($hasCreatedAt && $date !== '') {
        $datePart = substr($date, 0, 10);
        // Basic sanity check
        if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $datePart)) {
            $pdo->rollBack();
            http_response_code(400);
            tx_edit_respond(false, 'Invalid date format. Use YYYY-MM-DD');
        }
        $timePart = $time !== '' ? substr($time, 0, 8) : '00:00:00';
        if (preg_match('/^\d{2}:\d{2}$/', $timePart)) {
            $timePart .= ':00';
        }
        if (!preg_match('/^\d{2}:\d{2}:\d{2}$/', $timePart)) {
            $pdo->rollBack();
            http_response_code(400);
            tx_edit_respond(false, 'Invalid time format. Use HH:MM or HH:MM:SS');
        }
        $createdAtValue = $datePart . ' ' . $timePart;
    }

    // Update transaction row
    $setTx = ['amount = ?', 'details = ?'];
    $paramsTx = [$newAmount, $newDetailsJson];

    if ($hasAdminNoteCol && $description !== '') {
        $setTx[] = 'admin_note = ?';
        $paramsTx[] = $description;
    }

    if ($hasCreatedAt && $createdAtValue !== null) {
        $setTx[] = 'created_at = ?';
        $paramsTx[] = $createdAtValue;
    }

    if ($hasUpdatedAt) {
        $setTx[] = 'updated_at = NOW()';
    }

    $paramsTx[] = $transactionId;

    $sqlTx = 'UPDATE transactions SET ' . implode(', ', $setTx) . ' WHERE id = ?';
    $updTx = $pdo->prepare($sqlTx);
    $updTx->execute($paramsTx);

    // Admin log (best effort)
    try {
        $logDetails = json_encode([
            'transaction_id' => $transactionId,
            'user_id' => $userId,
            'type' => $type,
            'status' => $status,
            'old_amount' => $oldAmount,
            'new_amount' => $newAmount,
            'description' => $description,
            'balance_delta' => $balanceDelta,
            'total_deposited_delta' => $totalDepositedDelta,
            'total_withdrawn_delta' => $totalWithdrawnDelta,
            'date' => $createdAtValue,
        ]);
        $logStmt = $pdo->prepare('INSERT INTO admin_logs (admin_id, action, target_type, target_id, details, created_at) VALUES (?, ?, ?, ?, ?, NOW())');
        $logStmt->execute([
            isset($_SESSION['admin_id']) ? (int)$_SESSION['admin_id'] : 1,
            'edit_transaction',
            'transaction',
            $transactionId,
            $logDetails,
        ]);
    } catch (Exception $e) {
        // ignore logging failure
    }

    $pdo->commit();

    $extra = [
        'transaction_id' => $transactionId,
        'type' => $type,
        'status' => $status,
        'old_amount' => $oldAmount,
        'new_amount' => $newAmount,
    ];
    if ($adjustBalance) {
        $extra['balance_delta'] = $balanceDelta;
        $extra['total_deposited_delta'] = $totalDepositedDelta;
        $extra['total_withdrawn_delta'] = $totalWithdrawnDelta;
    }

    tx_edit_respond(true, 'Transaction updated successfully', $extra);

} catch (Exception $e) {
    if (isset($pdo) && $pdo instanceof PDO && $pdo->inTransaction()) {
        $pdo->rollBack();
    }
    error_log('admin_edit_transaction error: ' . $e->getMessage());
    http_response_code(500);
    tx_edit_respond(false, 'Failed to update transaction');
}
