<?php

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

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

$response = ['success' => false, 'errors' => ['general' => 'Gagal memproses pesanan. Terjadi kesalahan tak terduga.']];

if (!isset($pdo) || !$pdo instanceof PDO) {
    http_response_code(500);
    error_log("FATAL Error in place_order.php: PDO object not available or invalid. Check include order and DB connection in index.php/db_connect.php.");
    $response['errors']['general'] = 'Koneksi database tidak siap.';
    echo json_encode($response);
    exit;
}

if (!Auth::isLoggedIn()) {
    $response['errors']['general'] = 'Sesi Anda telah berakhir. Silakan login kembali.';
    http_response_code(401);
    echo json_encode($response);
    exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    $response['errors']['general'] = 'Metode request tidak valid.';
    http_response_code(405);
    echo json_encode($response);
    exit;
}

try {
    $userId = $_SESSION['user_id'];
    $serviceId = filter_input(INPUT_POST, 'service', FILTER_VALIDATE_INT);
    $target = sanitize_input($_POST['target'] ?? '');
    $quantity = filter_input(INPUT_POST, 'quantity', FILTER_VALIDATE_INT);
    $errors = [];

    if (!$serviceId) { $errors['service'] = 'Layanan wajib dipilih.'; }
    if (empty($target)) { $errors['target'] = 'Target wajib diisi.'; }
    if (!$quantity || $quantity <= 0) { $errors['quantity'] = 'Jumlah pesanan harus bilangan bulat positif.'; }

    if (!empty($errors)) {
        $response['errors'] = $errors;
        echo json_encode($response);
        exit;
    }

    $pdo->beginTransaction();

    $stmtService = $pdo->prepare("
        SELECT
            s.id as local_service_id, s.name as service_name,
            s.price_per_1000, s.min_order, s.max_order, s.provider_service_id,
            c.name as category_name,
            p.api_url, p.api_id, p.api_key, p.secret_key
        FROM services s
        JOIN providers p ON s.provider_id = p.id
        JOIN categories c ON s.category_id = c.id
        WHERE s.id = :sid AND s.status = 'active' AND p.status = 'active' AND c.status = 'active'
        LIMIT 1
        FOR UPDATE
    ");
    $stmtService->bindParam(':sid', $serviceId, PDO::PARAM_INT);
    $stmtService->execute();
    $serviceAndProvider = $stmtService->fetch(PDO::FETCH_ASSOC);

    $stmtUser = $pdo->prepare("SELECT balance FROM users WHERE id = :uid FOR UPDATE");
    $stmtUser->bindParam(':uid', $userId, PDO::PARAM_INT);
    $stmtUser->execute();
    $user = $stmtUser->fetch(PDO::FETCH_ASSOC);

    if (!$serviceAndProvider) { throw new Exception("Layanan, Kategori, atau Provider tidak valid/aktif.", 1); }
    if (!$user) { throw new Exception("Data pengguna tidak ditemukan.", 2); }
    if ($quantity < $serviceAndProvider['min_order']) { throw new Exception("Jumlah pesanan kurang dari minimum ({$serviceAndProvider['min_order']}).", 3); }
    if ($quantity > $serviceAndProvider['max_order']) { throw new Exception("Jumlah pesanan melebihi maksimum ({$serviceAndProvider['max_order']}).", 4); }

    $totalPrice = round(($quantity / 1000) * $serviceAndProvider['price_per_1000'], 2);
    if ($user['balance'] < $totalPrice) { throw new Exception("Saldo Anda tidak mencukupi (Rp " . number_format($user['balance'], 0, ',', '.') . ").", 5); }

    $balanceBefore = $user['balance'];
    $newBalance = $user['balance'] - $totalPrice;

    $stmtUpdateBalance = $pdo->prepare("UPDATE users SET balance = :new_balance WHERE id = :uid");
    $stmtUpdateBalance->bindParam(':new_balance', $newBalance);
    $stmtUpdateBalance->bindParam(':uid', $userId, PDO::PARAM_INT);
    if (!$stmtUpdateBalance->execute()) { throw new Exception("Gagal memperbarui saldo pengguna.", 6); }

    $initialStatus = 'pending';
    $sqlInsertOrder = "INSERT INTO orders (user_id, service_id, target, quantity, price, status, created_at, updated_at)
                       VALUES (:uid, :sid, :target, :qty, :price, :status, NOW(), NOW())";
    $stmtInsertOrder = $pdo->prepare($sqlInsertOrder);
    $stmtInsertOrder->bindParam(':uid', $userId, PDO::PARAM_INT);
    $stmtInsertOrder->bindParam(':sid', $serviceId, PDO::PARAM_INT);
    $stmtInsertOrder->bindParam(':target', $target);
    $stmtInsertOrder->bindParam(':qty', $quantity, PDO::PARAM_INT);
    $stmtInsertOrder->bindParam(':price', $totalPrice);
    $stmtInsertOrder->bindParam(':status', $initialStatus);
    if (!$stmtInsertOrder->execute()) { throw new Exception("Gagal menyimpan data pesanan awal.", 7); }
    $localOrderId = $pdo->lastInsertId();

    $logDescription = "Melakukan pesanan #{$localOrderId} ({$serviceAndProvider['service_name']})";
    log_balance_mutation(
        $pdo,
        $userId,
        'debit',
        'order_placement',
        $totalPrice,
        $balanceBefore,
        $newBalance,
        $logDescription,
        (string)$localOrderId,
        'web'
    );

    $apiUrl = $serviceAndProvider['api_url']."order";
    if (empty($apiUrl) || !filter_var($apiUrl, FILTER_VALIDATE_URL) || strpos($apiUrl, 'order') === false) {
         throw new Exception("URL API Order Provider tidak valid di database.", 99);
    }
    $apiId = $serviceAndProvider['api_id'];
    $apiKey = $serviceAndProvider['api_key'];
    $secretKey = $serviceAndProvider['secret_key'];
    $providerServiceId = $serviceAndProvider['provider_service_id'];

    $postData = [
        'api_id'     => $apiId, 'api_key'    => $apiKey, 'secret_key' => $secretKey,
        'service'    => $providerServiceId, 'target'     => $target, 'quantity'   => $quantity
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $apiUrl); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 60);
    $apiResultJson = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlError = curl_error($ch); curl_close($ch);

    $apiOrderId = null; $finalStatus = $initialStatus; $apiResponseLog = $apiResultJson ?: $curlError ?: "HTTP: " . $httpCode; $apiErrorMessage = null;
    if ($curlError) { $finalStatus = 'error'; $apiErrorMessage = "Gagal menghubungi API provider: " . $curlError; error_log($apiErrorMessage); }
    elseif ($httpCode !== 200) { $finalStatus = 'error'; $apiErrorMessage = "API provider mengembalikan HTTP status: " . $httpCode; error_log($apiErrorMessage . " | Response: " . substr($apiResponseLog, 0, 200)); }
    else { $apiResult = json_decode($apiResultJson, true); if (json_last_error() !== JSON_ERROR_NONE) { $finalStatus = 'error'; $apiErrorMessage = "Gagal membaca respons API (JSON tidak valid)"; error_log($apiErrorMessage . " | Response: " . substr($apiResponseLog, 0, 200)); } elseif (isset($apiResult['response']) && $apiResult['response'] === true && isset($apiResult['data']['id'])) { $apiOrderId = $apiResult['data']['id']; $finalStatus = 'processing'; error_log("Order success via API for local order ID ($localOrderId). Provider Order ID: $apiOrderId"); } else { $finalStatus = 'error'; $apiErrorMessage = $apiResult['data']['msg'] ?? 'API provider mengembalikan respons gagal.'; error_log("API Order Failed for local order ID ($localOrderId): " . $apiErrorMessage); $response['errors']['general'] = "Provider: " . $apiErrorMessage; } }

    $sqlUpdateOrder = "UPDATE orders SET status = :status, api_order_id = :api_oid, api_response = :resp, updated_at = NOW() WHERE id = :oid";
    $stmtUpdateOrder = $pdo->prepare($sqlUpdateOrder); $stmtUpdateOrder->bindParam(':status', $finalStatus); $stmtUpdateOrder->bindParam(':api_oid', $apiOrderId); $stmtUpdateOrder->bindParam(':resp', $apiResponseLog); $stmtUpdateOrder->bindParam(':oid', $localOrderId, PDO::PARAM_INT);
    if (!$stmtUpdateOrder->execute()) { error_log("CRITICAL: Failed to update local order status/api_id for local order ID ($localOrderId) after API call. Final status was: $finalStatus"); if ($finalStatus !== 'error') { $pdo->commit(); $response['errors']['general'] = "Pesanan dikirim, tapi gagal update status lokal (ID: $localOrderId)."; $response['success'] = false; } else { throw new Exception("Gagal memperbarui status pesanan setelah API gagal.", 8); } }
    else { if ($finalStatus !== 'error') {
            $pdo->commit();
            $response = [
                'success' => true,
                'orderDetails' => [
                    'orderId' => $localOrderId,
                    'category' => $serviceAndProvider['category_name'] ?? 'N/A',
                    'service' => $serviceAndProvider['service_name'] ?? 'N/A',
                    'target' => $target,
                    'quantity' => $quantity,
                    'price' => $totalPrice,
                    'priceFormatted' => 'Rp ' . number_format($totalPrice, 0, ',', '.')
                ]
            ];
        } else { $pdo->rollBack(); if (!isset($response['errors']['general'])) { $response['errors']['general'] = $apiErrorMessage ?? 'Gagal mengirim pesanan ke provider.'; } } }

} catch (\Exception $e) {
    if ($pdo->inTransaction()) { $pdo->rollBack(); }
    error_log("Place Order Exception: " . $e->getMessage() . " | Code: " . $e->getCode());
    $errorCode = $e->getCode(); $field = 'general';
    if ($errorCode === 3 || $errorCode === 4) { $field = 'quantity'; }
    elseif ($errorCode === 1) { $field = 'service'; }
    $response['errors'][$field] = $e->getMessage();
    if (defined('DEBUG_MODE') && DEBUG_MODE === true && ($errorCode >= 6 || $errorCode == 99)) { $response['errors']['debug'] = "Code: " . $e->getCode() . " | " . $e->getMessage(); }
    if ($errorCode >= 6 || $errorCode == 99 || $errorCode == 503) { http_response_code(500); }
    elseif ($errorCode == 1 || $errorCode == 2) { http_response_code(400); }

} catch (\Throwable $e) {
    if ($pdo->inTransaction()) { $pdo->rollBack(); }
    error_log("Place Order Throwable: " . $e->getMessage());
    $response['errors']['general'] = "Terjadi kesalahan internal server yang tidak terduga.";
    if (defined('DEBUG_MODE') && DEBUG_MODE === true) { $response['errors']['debug_php'] = $e->getMessage(); }
    http_response_code(500);
}

echo json_encode($response);
exit;
?>
