<?php
header('Content-Type: application/json');
$response = ['success' => false, 'message' => 'Gagal memperbarui pesanan.', 'errors' => []];

require_once __DIR__ . '/../../../config/config.php';
require_once __DIR__ . '/../../../includes/session.php';
require_once __DIR__ . '/../../../lib/Auth.php';
require_once __DIR__ . '/../../../includes/functions.php';

if (!Auth::isLoggedIn() || $_SESSION['user_role'] !== 'admin') {
    http_response_code(403);
    $response['message'] = 'Akses ditolak.';
    echo json_encode($response);
    exit;
}

if (!isset($pdo) || !$pdo instanceof PDO) {
    http_response_code(500);
    error_log("PDO object not available in admin/update_order.php");
    $response['message'] = 'Koneksi database gagal.';
    echo json_encode($response);
    exit;
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    $response['message'] = 'Metode request tidak valid.';
    echo json_encode($response);
    exit;
}

try {
    $orderIdToUpdate = filter_input(INPUT_POST, 'order_id', FILTER_VALIDATE_INT);
    if (!$orderIdToUpdate) {
        throw new InvalidArgumentException('ID pesanan tidak valid.');
    }

    $newStatus = sanitize_input($_POST['status'] ?? null);
    $startCountInput = $_POST['start_count'] ?? null;
    $remainsInput = $_POST['remains'] ?? null;

    $errors = [];
    $setClauses = [];
    $params = [':order_id' => $orderIdToUpdate];

    $pdo->beginTransaction();

    $stmtOrder = $pdo->prepare("SELECT user_id, price, quantity, status as current_status FROM orders WHERE id = :order_id FOR UPDATE");
    $stmtOrder->bindParam(':order_id', $orderIdToUpdate, PDO::PARAM_INT);
    $stmtOrder->execute();
    $orderData = $stmtOrder->fetch(PDO::FETCH_ASSOC);

    if (!$orderData) {
        $pdo->rollBack();
        throw new InvalidArgumentException('Pesanan tidak ditemukan.');
    }

    $currentOrderStatus = $orderData['current_status'];
    $userIdForLog = $orderData['user_id'];
    $orderPrice = (float)$orderData['price'];
    $orderQuantity = (int)$orderData['quantity'];


    $validStatuses = ['pending', 'processing', 'in progress', 'success', 'error', 'partial', 'canceled'];
    if ($newStatus !== null) {
        if (in_array($newStatus, $validStatuses)) {
            if ($newStatus !== $currentOrderStatus) {
                $setClauses[] = "status = :status";
                $params[':status'] = $newStatus;
            }
        } else {
            $errors['status'] = 'Status tidak valid.';
        }
    } else {
        $newStatus = $currentOrderStatus; // Jika tidak ada status baru, gunakan status saat ini
    }


    if ($startCountInput !== null && $startCountInput !== '') {
         $startCount = filter_var($startCountInput, FILTER_VALIDATE_INT);
         if ($startCount === false || $startCount < 0) {
             $errors['start_count'] = 'Jumlah awal harus angka positif atau kosong.';
         } else {
             $setClauses[] = "start_count = :start_count";
             $params[':start_count'] = $startCount;
         }
    } elseif ($startCountInput === '') {
        $setClauses[] = "start_count = NULL";
    }

    if ($remainsInput !== null && $remainsInput !== '') {
         $remains = filter_var($remainsInput, FILTER_VALIDATE_INT);
         if ($remains === false || $remains < 0) {
             $errors['remains'] = 'Jumlah kurang harus angka positif atau kosong.';
         } else {
             $setClauses[] = "remains = :remains";
             $params[':remains'] = $remains;
         }
    } elseif ($remainsInput === '') {
         $setClauses[] = "remains = NULL";
    }


    if (!empty($errors)) {
        $pdo->rollBack();
        http_response_code(400);
        $response['message'] = 'Periksa kembali input Anda.';
        $response['errors'] = $errors;
        echo json_encode($response);
        exit;
    }

    $refundAmount = 0;
    if ($newStatus !== $currentOrderStatus && in_array($newStatus, ['error', 'canceled'])) {
        if ($currentOrderStatus !== 'success' && $currentOrderStatus !== 'error' && $currentOrderStatus !== 'canceled') {
            $refundAmount = $orderPrice;
        }
    } elseif ($newStatus !== $currentOrderStatus && $newStatus === 'partial' && $remainsInput !== null) {
        $remainsValue = (int)$remainsInput;
        if ($currentOrderStatus !== 'success' && $currentOrderStatus !== 'error' && $currentOrderStatus !== 'canceled' && $currentOrderStatus !== 'partial') {
            if ($orderQuantity > 0 && $remainsValue >= 0 && $remainsValue < $orderQuantity) {
                $pricePerUnit = $orderPrice / $orderQuantity;
                $refundAmount = round($remainsValue * $pricePerUnit, 2);
            }
        }
    }

    if ($refundAmount > 0) {
        $stmtUserBalance = $pdo->prepare("SELECT balance FROM users WHERE id = :user_id FOR UPDATE");
        $stmtUserBalance->bindParam(':user_id', $userIdForLog, PDO::PARAM_INT);
        $stmtUserBalance->execute();
        $userBalanceBeforeRefund = (float)$stmtUserBalance->fetchColumn();

        $newBalanceForUser = $userBalanceBeforeRefund + $refundAmount;
        $stmtUpdateUserBalance = $pdo->prepare("UPDATE users SET balance = :new_balance WHERE id = :user_id");
        $stmtUpdateUserBalance->bindParam(':new_balance', $newBalanceForUser);
        $stmtUpdateUserBalance->bindParam(':user_id', $userIdForLog, PDO::PARAM_INT);
        if (!$stmtUpdateUserBalance->execute()) {
            $pdo->rollBack();
            throw new RuntimeException("Gagal memperbarui saldo pengguna saat refund.");
        }

        log_balance_mutation(
            $pdo,
            $userIdForLog,
            'credit',
            'order_refund',
            $refundAmount,
            $userBalanceBeforeRefund,
            $newBalanceForUser,
            "Refund untuk pesanan #{$orderIdToUpdate} karena status diubah menjadi {$newStatus}.",
            (string)$orderIdToUpdate,
            'admin'
        );
    }


    if (empty($setClauses)) {
         $pdo->rollBack();
         http_response_code(400);
         $response['message'] = 'Tidak ada data yang diubah.';
         echo json_encode($response);
         exit;
    }

    $setClauses[] = "updated_at = NOW()";
    $sql = "UPDATE orders SET " . implode(', ', $setClauses) . " WHERE id = :order_id";

    $stmt = $pdo->prepare($sql);
    if ($stmt->execute($params)) {
        $pdo->commit();
        $response['success'] = true;
        $response['message'] = 'Pesanan berhasil diperbarui.';
        if ($refundAmount > 0) {
            $response['message'] .= " Saldo pengguna telah dikembalikan sebesar Rp " . number_format($refundAmount, 2, ',', '.');
        }
    } else {
        $pdo->rollBack();
        http_response_code(500);
        $response['message'] = 'Gagal memperbarui pesanan di database.';
    }


} catch (InvalidArgumentException $e) {
    if ($pdo->inTransaction()) { $pdo->rollBack(); }
    http_response_code(400);
    $response['message'] = $e->getMessage();
} catch (RuntimeException $e) {
    if ($pdo->inTransaction()) { $pdo->rollBack(); }
    error_log("Admin Update Order Runtime Error: " . $e->getMessage());
    $response['message'] = "Gagal memproses: " . $e->getMessage();
    http_response_code(500);
} catch (\PDOException $e) {
    if ($pdo->inTransaction()) { $pdo->rollBack(); }
    error_log("Admin Update Order DB Error: " . $e->getMessage());
    $response['message'] = "Terjadi kesalahan database.";
    http_response_code(500);
} catch (\Throwable $e) {
    if ($pdo->inTransaction()) { $pdo->rollBack(); }
    error_log("Admin Update Order General Error: " . $e->getMessage());
    $response['message'] = "Terjadi kesalahan internal server.";
    if (defined('DEBUG_MODE') && DEBUG_MODE === true) { $response['debug_php'] = $e->getMessage(); }
    http_response_code(500);
}

echo json_encode($response);
exit;
?>
