<?php
/**
 * POST /api/orders/fulfill_item.php
 * Body (JSON): { order_item_id, action } — action is 'fulfilled' or 'cancelled'.
 *
 * This is where a sale actually becomes real - only the seller who owns
 * this specific line item can call it, and only once (a pending item can
 * move to fulfilled or cancelled, but not back, and not twice).
 *
 * fulfilled: seller confirms they received payment and handed over the
 *   goods in person. This is what triggers the buyer's loyalty points -
 *   not checkout - since "confirmed" per the business rule means the sale
 *   actually happened, not just that a buyer clicked a button.
 * cancelled: the sale fell through (buyer never showed up, item wasn't as
 *   described, whatever). Stock is released back to the listing - if the
 *   listing had been marked "sold" because this reservation took it to
 *   zero, it goes back to "active" so it can be sold to someone else.
 *
 * After updating, the parent order's overall status is recomputed: once
 * every line item across every seller in that order is out of "pending"
 * (all fulfilled and/or cancelled), the order itself is marked completed -
 * or cancelled if literally every item was cancelled.
 */

require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../includes/response.php';
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/loyalty.php';
require_once __DIR__ . '/../includes/notifications.php';

only_post_allowed();
$sellerId = require_login();

$input = get_json_input();
$orderItemId = (int) ($input['order_item_id'] ?? 0);
$action = $input['action'] ?? '';

if ($orderItemId <= 0 || !in_array($action, ['fulfilled', 'cancelled'], true)) {
    send_error('A valid order_item_id and action (fulfilled|cancelled) are required.', 422);
}

$pdo = Database::connect();

try {
    $pdo->beginTransaction();

    $stmt = $pdo->prepare('
        SELECT oi.id, oi.order_id, oi.product_id, oi.seller_id, oi.quantity, oi.unit_price, oi.status,
               o.buyer_id, p.name AS product_name, p.quantity AS current_stock, p.status AS product_status
        FROM order_items oi
        JOIN orders o ON o.id = oi.order_id
        JOIN products p ON p.id = oi.product_id
        WHERE oi.id = ?
        FOR UPDATE
    ');
    $stmt->execute([$orderItemId]);
    $item = $stmt->fetch();

    if (!$item) {
        $pdo->rollBack();
        send_error('Order item not found.', 404);
    }
    if ((int) $item['seller_id'] !== $sellerId) {
        $pdo->rollBack();
        send_error('You can only confirm sales for your own listings.', 403);
    }
    if ($item['status'] !== 'pending') {
        $pdo->rollBack();
        send_error("This item is already {$item['status']} - it can't be changed again.", 409);
    }

    $stmt = $pdo->prepare('UPDATE order_items SET status = ? WHERE id = ?');
    $stmt->execute([$action, $orderItemId]);

    $lineTotal = (float) $item['unit_price'] * (int) $item['quantity'];

    if ($action === 'fulfilled') {
        $points = (int) floor($lineTotal * points_per_dollar_spent($pdo));
        award_loyalty_points($pdo, (int) $item['buyer_id'], $points, "Purchase fulfilled - order #{$item['order_id']} ({$item['product_name']})");
        create_notification(
            $pdo, (int) $item['buyer_id'], 'order_fulfilled',
            "Your order for \"{$item['product_name']}\" (order #{$item['order_id']}) is complete. You earned $points loyalty point(s)."
        );
    } else {
        // Release the reserved stock back to the listing.
        $restoredStock = (int) $item['current_stock'] + (int) $item['quantity'];
        $newStatus = $item['product_status'] === 'sold' ? 'active' : $item['product_status'];
        $stmt = $pdo->prepare('UPDATE products SET quantity = ?, status = ? WHERE id = ?');
        $stmt->execute([$restoredStock, $newStatus, $item['product_id']]);

        create_notification(
            $pdo, (int) $item['buyer_id'], 'order_item_cancelled',
            "Your order for \"{$item['product_name']}\" (order #{$item['order_id']}) was cancelled by the seller."
        );
    }

    // Recompute the parent order's overall status now that one of its
    // items changed - an order can span multiple sellers, so this only
    // resolves once every line item (from every seller) is out of pending.
    $stmt = $pdo->prepare('SELECT status FROM order_items WHERE order_id = ?');
    $stmt->execute([$item['order_id']]);
    $allStatuses = $stmt->fetchAll(PDO::FETCH_COLUMN);

    if (!in_array('pending', $allStatuses, true)) {
        // All items are now fulfilled and/or cancelled (no more pending).
        // If literally every one was cancelled, the order itself is
        // cancelled; otherwise (at least one fulfilled) it's completed.
        $orderStatus = empty(array_diff($allStatuses, ['cancelled'])) ? 'cancelled' : 'completed';
        $stmt = $pdo->prepare('UPDATE orders SET status = ? WHERE id = ?');
        $stmt->execute([$orderStatus, $item['order_id']]);
    }

    $pdo->commit();
} catch (Throwable $e) {
    $pdo->rollBack();
    send_error('Could not update this item. Please try again.', 500, APP_ENV === 'local' ? [$e->getMessage()] : []);
}

send_json(true, $action === 'fulfilled' ? 'Sale confirmed.' : 'Order item cancelled and stock restored.');
