<?php

function _fetchFromApi($url)
{
    $curl = curl_init();
    curl_setopt_array($curl, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 20,
        CURLOPT_CUSTOMREQUEST => 'GET'
    ]);
    $response = curl_exec($curl);
    $err = curl_error($curl);
    curl_close($curl);

    if ($err || !$response)
        return [];

    $decoded = json_decode($response, true);
    if (is_array($decoded)) {
        if (!empty($decoded['packages']) && is_array($decoded['packages'])) {
            return $decoded['packages'];
        }
        if (isset($decoded[0]) && is_string($decoded[0])) {
            return $decoded;
        }
    }

    $clean = trim($response, '"');
    if (strpos($clean, ',') !== false) {
        return explode(',', $clean);
    }
    if (preg_match('/^[A-Z0-9]{5,}$/', $clean)) {
        return [$clean];
    }
    return [];
}

function fetchDelhiveryWaybills($baseUrl, $apiToken, $count = 1)
{
    if ($count < 1)
        return [];

    $collected = [];
    $attempts = 0;
    // Safety limit: max attempts = count + 5
    $maxAttempts = $count + 5;

    while (count($collected) < $count && $attempts < $maxAttempts) {
        $attempts++;
        $needed = $count - count($collected);

        $fetchUrl = rtrim($baseUrl, '/') . '/waybill/api/fetch/json/?token=' . $apiToken . '&fetch=' . $needed;
        $batch = _fetchFromApi($fetchUrl);

        if (!empty($batch)) {
            foreach ($batch as $wb) {
                $wb = trim($wb);
                if ($wb !== '') {
                    $collected[] = $wb;
                }
            }
        } else {
            // If we got nothing, wait briefly before small retry
            usleep(200000);
        }

        // If we got *some* (e.g. 1) but not enough, the loop will continue to get more.
    }

    return array_slice($collected, 0, $count);
}

function syncBookingWithDelhivery($pdo, $courierData, $shipmentData)
{
    if (empty($courierData['api_key'])) {
        return ['success' => false, 'synced' => false, 'message' => 'Delhivery API Key is missing'];
    }
    if (empty($courierData['api_url'])) {
        return ['success' => false, 'synced' => false, 'message' => 'Delhivery API URL is missing'];
    }

    $apiToken = $courierData['api_key'];
    $baseUrl = rtrim($courierData['api_url'], '/');
    $apiUrl = $baseUrl . '/api/cmu/create.json';

    $packages = $shipmentData['package_details'] ?? [];
    // Fallback if package_details missing (legacy calls)
    if (empty($packages)) {
        $packages = [
            [
                'length' => $shipmentData['length'] ?? 10,
                'width' => $shipmentData['width'] ?? 10,
                'height' => $shipmentData['height'] ?? 10,
                'actual_weight' => $shipmentData['weight'] ? ($shipmentData['weight'] / 1000) : 0.5,
                'boxes' => $shipmentData['quantity'] ?? 1
            ]
        ];
    }

    // Flatten packages (expand 'boxes' count into individual items)
    $flatPackages = [];
    foreach ($packages as $pkg) {
        $count = max(1, (int) ($pkg['boxes'] ?? 1));
        for ($i = 0; $i < $count; $i++) {
            $flatPackages[] = $pkg;
        }
    }

    $totalPackages = count($flatPackages);
    $isMPS = $totalPackages > 1;

    // Fetch Waybills
    $waybills = [];
    if ($totalPackages > 0) {
        $waybills = fetchDelhiveryWaybills($baseUrl, $apiToken, $totalPackages);
        if (count($waybills) < $totalPackages) {
            return ['success' => false, 'synced' => false, 'message' => 'Failed to fetch sufficient waybills from Delhivery (Got ' . count($waybills) . ', need ' . $totalPackages . ')'];
        }
    }

    $masterWaybill = $waybills[0] ?? '';
    $shipments = [];

    $paymentMode = $shipmentData['payment_mode'] ?? 'Prepaid';
    $codTotal = ($paymentMode === 'COD') ? (float) ($shipmentData['cod_amount'] ?? 0) : 0;
    $invoiceValue = (float) ($shipmentData['invoice_value'] ?? 0);

    // Distribute COD: Full amount on Master (first pkg), 0 on others? 
    // Or if Delhivery requires distribution, logic might vary. 
    // Safest for MPS is usually putting COD on Master.

    foreach ($flatPackages as $index => $pkg) {
        $isMaster = ($index === 0);
        $currentWaybill = $waybills[$index];

        $pkgCod = $isMaster ? $codTotal : 0;

        // Prepare Shipment Item
        $item = [
            'name' => $shipmentData['consignee_name'],
            'add' => $shipmentData['consignee_address'],
            'pin' => $shipmentData['consignee_pin'],
            'city' => $shipmentData['consignee_city'],
            'state' => $shipmentData['consignee_state'],
            'country' => $shipmentData['consignee_country'] ?? 'India',
            'phone' => $shipmentData['consignee_phone'],
            'order' => $shipmentData['booking_ref_id'],
            'payment_mode' => $paymentMode,
            'return_pin' => '',
            'return_city' => '',
            'return_phone' => '',
            'return_add' => '',
            'return_state' => '',
            'return_country' => '',
            'products_desc' => $shipmentData['product_desc'] ?? 'Package',
            'hsn_code' => '',
            'cod_amount' => $pkgCod,
            'order_date' => null,
            'total_amount' => ($invoiceValue > 0) ? $invoiceValue : $codTotal, // Declared Value
            'seller_add' => '',
            'seller_name' => '',
            'seller_inv' => $shipmentData['invoice_no'] ?? '',
            'quantity' => '1',
            'waybill' => $currentWaybill,
            'shipment_width' => (string) ($pkg['width'] ?? 10),
            'shipment_height' => (string) ($pkg['height'] ?? 10),
            'shipment_length' => (string) ($pkg['length'] ?? 10),
            'weight' => (string) (($pkg['actual_weight'] ?? 0.5) * 1000), // gms
            'shipping_mode' => $shipmentData['shipping_mode'] ?? 'Surface',
            'address_type' => 'home'
        ];

        if ($isMPS) {
            $item['shipment_type'] = 'MPS';
            $item['master_id'] = $masterWaybill;
            $item['mps_children'] = (string) $totalPackages;
            $item['mps_amount'] = (string) $codTotal;
        }

        $shipments[] = $item;
    }

    $shipmentPayload = [
        'shipments' => $shipments,
        'pickup_location' => [
            'name' => $shipmentData['pickup_location_name']
        ]
    ];

    // Delhivery expects format=json&data=<json>
    $postFields = 'format=json&data=' . json_encode($shipmentPayload);

    $curl = curl_init();
    curl_setopt_array($curl, [
        CURLOPT_URL => $apiUrl,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => '',
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => 'POST',
        CURLOPT_POSTFIELDS => $postFields,
        CURLOPT_HTTPHEADER => [
            'Authorization: Token ' . $apiToken,
            'Accept: application/json'
        ],
    ]);

    $response = curl_exec($curl);
    $err = curl_error($curl);
    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    curl_close($curl);

    if ($err) {
        return ['success' => false, 'synced' => false, 'message' => 'cURL Error: ' . $err];
    }

    $responseData = json_decode($response, true);

    if ($httpCode >= 200 && $httpCode < 300) {
        // Response format: { "packages": [ { "status": "Success", "waybill": "..." }, ... ] }
        // Check if ANY package failed? Or all success?
        $packagesResp = $responseData['packages'] ?? [];
        if (!empty($packagesResp)) {
            $first = $packagesResp[0];
            if (($first['status'] ?? '') === 'Success' || ($first['status'] ?? '') === 'Fail') {
                // Wait, if Fail, we should return error.
                if (($first['status'] ?? '') !== 'Success') {
                    return [
                        'success' => false,
                        'synced' => false,
                        'api_response' => $responseData,
                        'message' => 'Delhivery Error: ' . ($first['remarks'][0] ?? 'Unknown')
                    ];
                }

                // Success
                return [
                    'success' => true,
                    'synced' => true,
                    'waybill' => $masterWaybill, // Main waybill
                    'api_response' => $responseData,
                    'message' => 'Booking synced with Delhivery'
                ];
            }
        }

        // Handle "upload_wbn" key if present (sometimes returned for pre-generated waybills?)
        // Standard CMU returns packages array.
    }

    return [
        'success' => false,
        'synced' => false,
        'api_response' => $responseData,
        'message' => 'Delhivery sync failed: ' . $response
    ];
}

function trackBookingWithDelhivery($pdo, $courierData, $waybillNo)
{
    if (empty($courierData['api_key'])) {
        return ['success' => false, 'message' => 'Delhivery API Key is missing'];
    }
    if (empty($courierData['api_url'])) {
        return ['success' => false, 'message' => 'Delhivery API URL is missing'];
    }

    $apiToken = $courierData['api_key'];
    $url = rtrim($courierData['api_url'], '/') . '/api/v1/packages/json/?waybill=' . urlencode($waybillNo) . '&verbose=0';

    $curl = curl_init();
    curl_setopt_array($curl, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => '',
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => 'GET',
        CURLOPT_HTTPHEADER => [
            'Authorization: Token ' . $apiToken,
            'Accept: application/json'
        ],
    ]);

    $response = curl_exec($curl);
    $err = curl_error($curl);
    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    curl_close($curl);

    if ($err) {
        return ['success' => false, 'message' => 'cURL Error: ' . $err];
    }

    $responseData = json_decode($response, true);

    if ($httpCode >= 200 && $httpCode < 300 && !empty($responseData['ShipmentData'])) {
        return [
            'success' => true,
            'data' => $responseData['ShipmentData'][0] ?? [],
            'full_response' => $responseData
        ];
    }

    return [
        'success' => false,
        'message' => 'Tracking failed or no data',
        'response' => $responseData
    ];
}

?>
