<?php
/**
 * update_order_status.php
 * Lets someone manually flip a stuck PENDING order to SUCCESS or FAILURE
 * from the Transactions page. Mirrors the same webhook/report/notification
 * steps the automatic resolvers already do, so the merchant's integration
 * behaves identically either way.
 *
 * Permissions:
 *  - Admin: any order, live or test (used to unstick a real payment that
 *    verification never caught).
 *  - User (merchant): ONLY their own orders that are in Test Mode
 *    (is_test = 1). This exists so a merchant can trigger their webhook
 *    on demand while integrating, without needing a real payment - it is
 *    deliberately NOT available on live orders, since letting a merchant
 *    flip their own real order to SUCCESS without an actual payment would
 *    let them fake a paid webhook to their own downstream system.
 *
 * Only ever transitions an order that is currently PENDING - already
 * resolved orders can't be flipped again from here.
 */

session_start();
include "config.php";
include_once __DIR__ . '/../includes/webhook_lib.php';
include_once __DIR__ . '/../includes/notify_lib.php';
include_once __DIR__ . '/../includes/subscription_lib.php';

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

if (!isset($_SESSION['username'])) {
    echo json_encode(['status' => false, 'message' => 'Unauthorized']);
    exit;
}

$userdata = mysqli_fetch_assoc(mysqli_query($conn, "SELECT * FROM users WHERE mobile = '" . mysqli_real_escape_string($conn, $_SESSION['username']) . "'"));

if (!$userdata) {
    echo json_encode(['status' => false, 'message' => 'Unauthorized']);
    exit;
}

$order_id   = trim($_POST['order_id'] ?? '');
$new_status = trim($_POST['new_status'] ?? ''); // 'SUCCESS' or 'FAILURE'

if ($order_id === '' || !in_array($new_status, ['SUCCESS', 'FAILURE'], true)) {
    echo json_encode(['status' => false, 'message' => 'Invalid request']);
    exit;
}

// Look up the order first - permission depends on who owns it and whether
// it's a test order, so we need this before deciding if the request is
// even allowed.
$stmt = $conn->prepare("SELECT * FROM orders WHERE order_id = ?");
$stmt->bind_param("s", $order_id);
$stmt->execute();
$orderCheck = $stmt->get_result()->fetch_assoc();
$stmt->close();

if (!$orderCheck) {
    echo json_encode(['status' => false, 'message' => 'Order not found']);
    exit;
}

$isAdmin = ($userdata['role'] == 'Admin');
$isOwnTestOrder = ($userdata['role'] == 'User')
    && $orderCheck['user_token'] === $userdata['user_token']
    && (int)$orderCheck['is_test'] === 1;

if (!$isAdmin && !$isOwnTestOrder) {
    echo json_encode(['status' => false, 'message' => 'Permission Denied: you can only resolve your own Test Mode orders this way.']);
    exit;
}

// Atomic claim: only ever move an order OUT of PENDING here, and only once -
// if two tabs (or a user + the automatic watcher) race on the same order,
// only one of them actually does anything below. Re-checks ownership/test
// flag here too (not just above) so a live order can't slip through a race.
if ($isAdmin) {
    $stmt = $conn->prepare("UPDATE orders SET status = ? WHERE order_id = ? AND status = 'PENDING'");
    $stmt->bind_param("ss", $new_status, $order_id);
} else {
    $stmt = $conn->prepare("UPDATE orders SET status = ? WHERE order_id = ? AND status = 'PENDING' AND user_token = ? AND is_test = 1");
    $stmt->bind_param("sss", $new_status, $order_id, $userdata['user_token']);
}
$stmt->execute();
$wonTheRace = $stmt->affected_rows > 0;
$stmt->close();

if (!$wonTheRace) {
    echo json_encode(['status' => false, 'message' => 'This order is no longer Pending - it may have already been resolved.']);
    exit;
}

$stmt = $conn->prepare("SELECT * FROM orders WHERE order_id = ?");
$stmt->bind_param("s", $order_id);
$stmt->execute();
$order = $stmt->get_result()->fetch_assoc();
$stmt->close();

$user_token = $order['user_token'];
$amount     = $order['amount'];
$method     = $order['Method'] ?? $order['method'] ?? 'UPI';
$remark1    = $order['remark1'] ?? '';

$stmt = $conn->prepare("SELECT * FROM users WHERE user_token = ?");
$stmt->bind_param("s", $user_token);
$stmt->execute();
$merchant = $stmt->get_result()->fetch_assoc();
$stmt->close();

$merchant_id   = $merchant['id'] ?? null;
$callback_url  = $merchant['callback_url'] ?? '';

$actorNote = $isAdmin ? 'Manually marked ' : 'Manually marked (Test Mode) ';

if ($new_status === 'SUCCESS') {

    $utr = $order['utr'];
    if (empty($utr)) {
        $utr = 'MANUAL-' . strtoupper(substr(md5($order_id . time()), 0, 10));
        $stmtU = $conn->prepare("UPDATE orders SET utr = ? WHERE order_id = ?");
        $stmtU->bind_param("ss", $utr, $order_id);
        $stmtU->execute();
        $stmtU->close();
    }

    $adminNote = $actorNote . 'Success';
    $manualVpa = 'Manual';
    $stmtR = $conn->prepare("INSERT INTO reports (transactionId, status, order_id, vpa, user_name, paymentApp, amount, user_token, transactionNote, merchantTransactionId, user_id) VALUES (?, 'TXN_SUCCESS', ?, ?, 'NULL', ?, ?, ?, ?, ?, ?)");
    $stmtR->bind_param("ssssssssi", $utr, $order_id, $manualVpa, $method, $amount, $user_token, $adminNote, $order_id, $merchant_id);
    $stmtR->execute();
    $stmtR->close();

    if ($merchant_id) {
        incrementTransactionUsage($conn, $merchant_id);
        send_payment_success_notification($conn, $merchant_id, $order_id, $amount, $utr, $method);

        // Same rule as the automatic resolver: no commission on Test Mode
        // orders (not real money) or on the platform's own
        // subscription/wallet-topup orders (merchant paying the platform,
        // not receiving a payment).
        if (!(int)($order['is_test'] ?? 0) && $remark1 !== 'test1' && strpos((string)$remark1, 'WALLET_TOPUP') !== 0) {
            include_once __DIR__ . '/../includes/wallet_lib.php';
            deduct_commission_on_success($conn, $merchant_id, $order_id, $amount);
        }
    }

    send_webhook($conn, $merchant_id, $callback_url, 'payment.success', [
        'order_id'   => htmlspecialchars_decode($order_id),
        'txn_id'     => $utr,
        'status'     => 'Success',
        'amount'     => $amount,
        'pay_amount' => $amount,
        'utr'        => $utr,
        'remark1'    => $remark1,
    ], $order_id);

    echo json_encode(['status' => true, 'message' => 'Order marked Success']);

} else {

    if ($merchant_id) {
        send_payment_failed_notification($conn, $merchant_id, $order_id, $amount, $method, $actorNote . 'Failed');
    }

    send_webhook($conn, $merchant_id, $callback_url, 'payment.failed', [
        'order_id' => htmlspecialchars_decode($order_id),
        'status'   => 'Failed',
        'amount'   => $amount,
        'reason'   => $actorNote . 'Failed',
    ], $order_id);

    echo json_encode(['status' => true, 'message' => 'Order marked Failed']);
}
