<?php
/**
 * CourierIT1 courier adapter.
 * CourierIT1 mirrors the Packie JSON API shape closely enough that the same
 * package, quote, create, PDF, and relist failure flow can be reused here.
 */

if (!class_exists('Logger')) require_once __DIR__ . '/../logger.php';

function courierit1_config(): array {
    global $pm;
    return $pm && method_exists($pm, 'getShipConfig') ? $pm->getShipConfig() : [];
}

function courierit1_base_url(array $config = []): string {
    if (!$config) $config = courierit1_config();
    return rtrim((string)($config['base_url'] ?? 'https://courierit1.net.nz/api'), '/');
}

function courierit1_web_base_url(array $config = []): string {
    $api = courierit1_base_url($config);
    return preg_replace('~/api$~i', '', $api) ?: 'https://courierit1.net.nz';
}

function courierit1_headers(bool $json = true): ?array {
    global $pm;
    if (!$pm) return null;
    $pm->ensureShipTokenFresh();
    $token = $pm->getShipToken();
    if (!$token) return null;

    $headers = [
        'Accept: application/json, text/javascript, */*; q=0.01',
        'Authorization: Bearer ' . $token,
        'Access-Control-Expose-Headers: *',
        'Access-Control-Allow-Origin: *',
        'X-Requested-With: XMLHttpRequest',
    ];
    if ($json) $headers[] = 'Content-Type: application/json; charset=utf-8';
    return $headers;
}

function courierit1_request_json(string $method, string $path, $payload = null): array {
    $headers = courierit1_headers($payload !== null);
    if (!$headers) {
        return ['success' => false, 'message' => 'CourierIT1 credentials are missing or invalid.', '_http' => 0, '_raw' => ''];
    }

    $url = courierit1_base_url() . '/' . ltrim($path, '/');
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 25);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
    if ($payload !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
    }
    $raw = curl_exec($ch);
    $http = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $err = curl_error($ch);
    curl_close($ch);

    $decoded = json_decode((string)$raw, true);
    if (!is_array($decoded)) {
        return [
            'success' => false,
            'message' => $err !== '' ? $err : 'CourierIT1 returned a non-JSON response.',
            '_http' => $http,
            '_raw' => (string)$raw,
        ];
    }
    $decoded['_http'] = $http;
    $decoded['_raw'] = (string)$raw;
    return $decoded;
}

function courierit1_request_raw(string $method, string $path, $payload = null): array {
    $headers = courierit1_headers($payload !== null);
    if (!$headers) {
        return ['success' => false, 'message' => 'CourierIT1 credentials are missing or invalid.', '_http' => 0, '_raw' => ''];
    }

    $url = courierit1_base_url() . '/' . ltrim($path, '/');
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 25);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
    if ($payload !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
    }
    $raw = curl_exec($ch);
    $http = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $err = curl_error($ch);
    curl_close($ch);

    $decoded = json_decode((string)$raw, true);
    return [
        'success' => $err === '' && $http >= 200 && $http < 300,
        'message' => $err,
        'decoded' => is_array($decoded) ? $decoded : null,
        '_http' => $http,
        '_raw' => (string)$raw,
    ];
}

function courierit1_print_client_result($value): string {
    if (is_string($value)) return trim($value);
    if (!is_array($value)) return '';
    foreach (['result', 'data', 'url', 'printUrl', 'print_url', 'clientPrint', 'client_print'] as $key) {
        if (isset($value[$key])) {
            $found = courierit1_print_client_result($value[$key]);
            if ($found !== '') return $found;
        }
    }
    return '';
}

function courierit1_provider_stock_options_result(): array {
    $res = courierit1_request_json('GET', 'Stocks');
    if (empty($res['success']) && !isset($res['result'])) {
        $res = courierit1_request_json('GET', 'stocks');
    }
    if (empty($res['success']) && !isset($res['result'])) {
        return [
            'success' => false,
            'error' => afri_extract_carrier_error($res, (string)($res['_raw'] ?? '')),
            'options' => [],
        ];
    }

    $rows = is_array($res['result'] ?? null) ? $res['result'] : [];
    $company_rows = array_values(array_filter($rows, function ($stock) {
        return is_array($stock) && !empty($stock['companyId']);
    }));
    if ($company_rows) $rows = $company_rows;

    $options = [];
    foreach ($rows as $stock) {
        if (!is_array($stock)) continue;
        $id = trim((string)($stock['id'] ?? ''));
        if ($id === '') continue;
        $options[] = [
            'id' => $id,
            'label' => (string)($stock['name'] ?? ('CourierIT1 stock ' . $id)),
            'serviceType' => (int)($stock['serviceType'] ?? 0),
            'length' => (float)($stock['length'] ?? 0),
            'width' => (float)($stock['width'] ?? 0),
            'height' => (float)($stock['height'] ?? 0),
            'weight' => (float)($stock['weight'] ?? 0),
            'cubicWeight' => (float)($stock['cubicWeight'] ?? 0),
            'companyId' => $stock['companyId'] ?? null,
        ];
    }

    return ['success' => true, 'error' => '', 'options' => $options];
}

function courierit1_provider_stock_options(): array {
    $result = courierit1_provider_stock_options_result();
    return is_array($result['options'] ?? null) ? $result['options'] : [];
}

function courierit1_package_mapping(mysqli $db, string $package_code): ?array {
    $code = strtoupper(preg_replace('/[^A-Z0-9]/', '', $package_code));
    if ($code === '') return null;
    $stmt = $db->prepare("
        SELECT provider_stock_id, provider_service_type, provider_label, length, width, height, weight
        FROM pp_provider_package_map
        WHERE provider_slug = 'courierit1' AND package_code = ? AND is_enabled = 1
        LIMIT 1
    ");
    $stmt->bind_param('s', $code);
    $stmt->execute();
    $row = $stmt->get_result()->fetch_assoc();
    return $row ?: null;
}

function courierit1_find_stock_for_package(mysqli $db, string $stock_id): ?array {
    $package = function_exists('afri_resolve_package_preset') ? afri_resolve_package_preset($db, $stock_id) : null;
    $code = strtoupper(preg_replace('/[^A-Z0-9]/', '', (string)($package['code'] ?? $stock_id)));
    $map = courierit1_package_mapping($db, $code);

    $stock_ref = trim((string)($map['provider_stock_id'] ?? ''));
    $stocks = courierit1_provider_stock_options();
    foreach ($stocks as $stock) {
        if ($stock_ref !== '' && (string)($stock['id'] ?? '') === $stock_ref) {
            return [
                'id' => (string)$stock['id'],
                'name' => (string)($stock['label'] ?? $stock['name'] ?? ''),
                'serviceType' => (int)($stock['serviceType'] ?? 1),
                'length' => (float)($stock['length'] ?? 0),
                'width' => (float)($stock['width'] ?? 0),
                'height' => (float)($stock['height'] ?? 0),
                'weight' => (float)($stock['weight'] ?? 0),
            ];
        }
    }

    foreach ($stocks as $stock) {
        $label = strtoupper((string)($stock['label'] ?? $stock['name'] ?? ''));
        if ($code !== '' && preg_match('/\b' . preg_quote($code, '/') . '\b/', $label)) {
            return [
                'id' => (string)$stock['id'],
                'name' => (string)($stock['label'] ?? $stock['name'] ?? ''),
                'serviceType' => (int)($stock['serviceType'] ?? 1),
                'length' => (float)($stock['length'] ?? 0),
                'width' => (float)($stock['width'] ?? 0),
                'height' => (float)($stock['height'] ?? 0),
                'weight' => (float)($stock['weight'] ?? 0),
            ];
        }
    }

    if ($package) {
        return [
            'id' => $stock_ref !== '' ? $stock_ref : '1',
            'name' => (string)($map['provider_label'] ?? $package['name'] ?? $code),
            'serviceType' => (int)($map['provider_service_type'] ?? 1),
            'length' => (float)($map['length'] ?? $package['length'] ?? 0),
            'width' => (float)($map['width'] ?? $package['width'] ?? 0),
            'height' => (float)($map['height'] ?? $package['height'] ?? 0),
            'weight' => (float)($map['weight'] ?? $package['weight'] ?? 0),
        ];
    }

    return null;
}

function courierit1_find_order(string $shopify_num): ?array {
    $shopify_num = preg_replace('/\D+/', '', $shopify_num);
    if ($shopify_num === '') return null;

    foreach ([1, 2, 3, 4, 5, 0, 99] as $status) {
        $res = courierit1_request_json('GET', 'Orders/get-orders?status=' . $status . '&search=' . urlencode($shopify_num) . '&integrationId=0&page=1&perPage=5');
        foreach (($res['result']['orders'] ?? []) as $order) {
            if ((string)($order['orderNumber'] ?? '') === $shopify_num) {
                return $order;
            }
        }
    }

    return null;
}

function courierit1_normalize_address_array(array $address): array {
    foreach ($address as $key => $value) {
        if ($value === null) $address[$key] = '';
    }
    return $address;
}

function courierit1_build_payload(mysqli $db, $pm, string $order_name, string $stock_id, string $rate_id = ''): array {
    $shopify_num = preg_replace('/\D+/', '', $order_name);
    $order = courierit1_find_order($shopify_num);
    if (!$order) {
        return ['success' => false, 'error' => 'Order was not found in CourierIT1.'];
    }

    $stock = null;
    if ($stock_id === 'custom') {
        global $arg_w, $arg_l, $arg_h, $arg_weight;
        $stock = [
            'id' => '0',
            'name' => 'Custom Box',
            'serviceType' => 1,
            'height' => (float)$arg_h,
            'width' => (float)$arg_w,
            'length' => (float)$arg_l,
            'weight' => (float)$arg_weight,
        ];
    } else {
        $stock = courierit1_find_stock_for_package($db, $stock_id);
    }
    if (!$stock) {
        return ['success' => false, 'error' => 'Selected CourierIT1 stock/package could not be found.'];
    }

    $sender_raw = $pm ? $pm->senderDetails() : [];
    $sender_from_order = is_array($order['sender'] ?? null) ? $order['sender'] : [];
    $receiver = courierit1_normalize_address_array(is_array($order['receiver'] ?? null) ? $order['receiver'] : []);

    $sender_street = trim((string)($sender_raw['street'] ?? $sender_raw['streetAddress'] ?? $sender_from_order['street'] ?? $sender_from_order['address1'] ?? ''));
    $sender_city = trim((string)($sender_raw['city'] ?? $sender_from_order['city'] ?? ''));
    $sender_postcode = trim((string)($sender_raw['postcode'] ?? $sender_raw['postCode'] ?? $sender_from_order['postCode'] ?? $sender_from_order['postcode'] ?? ''));
    $sender_country = trim((string)($sender_raw['country'] ?? 'NZ'));
    $sender_suburb = trim((string)($sender_raw['suburb'] ?? $sender_from_order['suburb'] ?? $sender_city));

    if ($sender_street === '') $sender_street = '247 Cuba Street';
    if ($sender_city === '') $sender_city = 'Palmerston North';
    if ($sender_postcode === '') $sender_postcode = '4410';
    if ($sender_suburb === '') $sender_suburb = $sender_city;
    $shipping_description = trim((string)($order['shippingDescription'] ?? ''));
    $shipping_method = trim((string)($order['shippingMethod'] ?? ''));
    if ($shipping_description === '') $shipping_description = 'Fastest Delivery';
    if ($shipping_method === '') $shipping_method = $shipping_description;
    $declared_value = $order['totalPrice'] ?? $order['total'] ?? '';

    $payload = [
        'sender' => [
            'contactName' => (string)($sender_raw['contactName'] ?? $sender_from_order['contactName'] ?? ''),
            'company' => (string)($sender_raw['company'] ?? $sender_from_order['company'] ?? ''),
            'building' => (string)($sender_from_order['building'] ?? ''),
            'unit' => (string)($sender_from_order['unit'] ?? ''),
            'suburb' => $sender_suburb,
            'street' => $sender_street,
            'postCode' => $sender_postcode,
            'city' => $sender_city,
            'country' => $sender_country ?: 'NZ',
            'state' => (string)($sender_from_order['state'] ?? $sender_city),
            'phone' => (string)($sender_raw['phone'] ?? $sender_from_order['phone'] ?? ''),
            'email' => (string)($sender_raw['email'] ?? $sender_from_order['email'] ?? ''),
            'notes' => '',
        ],
        'receiver' => $receiver,
        'isInternational' => strtoupper((string)($receiver['country'] ?? 'NZ')) !== 'NZ',
        'integratedOrderId' => $order['id'],
        'integrationType' => 1,
        'shippingDescription' => $shipping_description,
        'shippingMethod' => $shipping_method,
        'hasDangerousGoods' => false,
        'signatureRequired' => !empty($order['signatureRequired']),
        'consignmentParcels' => [[
            'id' => is_numeric($stock['id']) ? (int)$stock['id'] : (string)$stock['id'],
            'height' => (float)$stock['height'],
            'width' => (float)$stock['width'],
            'length' => (float)$stock['length'],
            'itemSKU' => '',
            'weight' => (float)$stock['weight'],
            'quantity' => 1,
            'serviceType' => (int)($stock['serviceType'] ?: 1),
            'internationalDeclaredValue' => $declared_value !== '' ? number_format((float)$declared_value, 2, '.', '') : '',
            'dangerousGoodsRate' => 0,
            'markupRate' => 0,
        ]],
    ];

    return ['success' => true, 'order' => $order, 'stock' => $stock, 'payload' => $payload];
}

function courierit1_label_pdf_url($order_id): string {
    global $pm;
    if (!$pm || trim((string)$order_id) === '') return '';
    return $pm->shipUrl('consignments/pdf-labels-download/' . rawurlencode((string)$order_id) . '/parcels/true');
}

function courierit1_label_print_request($order_id): array {
    $id = is_numeric($order_id) ? (int)$order_id : $order_id;
    return courierit1_request_raw('POST', 'consignments/parcel-pdf-labelprint/true', [$id]);
}

if ($action == 'get_stock_quote') {
    global $db, $pm;
    $order_name = $_GET['order_name'] ?? '';
    $stock_id = trim((string)($_GET['stock_id'] ?? ''));
    $context = courierit1_build_payload($db, $pm, (string)$order_name, $stock_id);
    if (empty($context['success'])) {
        echo json_encode(['success' => false, 'error' => $context['error'] ?? 'Could not build CourierIT1 quote payload.']);
        exit;
    }

    $res = courierit1_request_json('POST', 'Consignments/calculate', $context['payload']);
    if (empty($res['success'])) {
        echo json_encode(['success' => false, 'error' => afri_extract_carrier_error($res, (string)($res['_raw'] ?? ''))]);
        exit;
    }

    $rates = is_array($res['result']['rates'] ?? null) ? $res['result']['rates'] : [];
    foreach ($rates as &$rate) {
        if (!is_array($rate)) continue;
        $rate['provider'] = 'courierit1';
        $rate['providerDisplayName'] = 'CourierIT1';
        $rate['stockId'] = $stock_id;
    }
    unset($rate);

    echo json_encode($rates);
    exit;
}

if ($action == 'get_stocks') {
    $stocks = function_exists('afri_list_package_presets') ? afri_list_package_presets($db) : [];
    echo json_encode($stocks);
    exit;
}

if ($action == 'print_label') {
    global $db, $pm, $arg_oid, $arg_staff, $arg_stock, $arg_rate, $arg_order_name;

    if (!function_exists('ecommerce_get_order_meta')) {
        $_ecom_slug = ($pm && method_exists($pm, 'getEcomSlug')) ? $pm->getEcomSlug() : 'shopify';
        $_ecom_file = dirname(__DIR__) . '/ecommerce/' . $_ecom_slug . '.php';
        if ($_ecom_slug !== '' && file_exists($_ecom_file)) include $_ecom_file;
    }

    $order_id = (string)($arg_oid ?? '');
    $order_name = (string)($arg_order_name ?? '');
    $shopify_num = preg_replace('/\D+/', '', $order_name);
    $tags = '';
    if (function_exists('ecommerce_get_order_meta') && $order_id !== '') {
        $meta = ecommerce_get_order_meta($order_id);
        if (is_array($meta)) {
            $shopify_num = preg_replace('/\D+/', '', (string)($meta['name'] ?? $order_name));
            $tags = (string)($meta['tags'] ?? '');
        }
    }

    $fail = function (string $message) use ($db, $order_id, $order_name, $shopify_num, $tags) {
        if (function_exists('afri_handle_label_failure')) {
            echo json_encode(afri_handle_label_failure($db, $order_id, $order_name, $shopify_num, $tags, 'CourierIT1', $message)) . "\n";
        } else {
            echo json_encode(['success' => false, 'error' => $message]) . "\n";
        }
        exit;
    };

    $context = courierit1_build_payload($db, $pm, $shopify_num ?: $order_name, (string)($arg_stock ?? 'none'), (string)($arg_rate ?? ''));
    if (empty($context['success'])) {
        Logger::warn('courierit1.print_label', 'payload_failed', ['order' => $order_name, 'stock' => $arg_stock ?? '', 'error' => $context['error'] ?? 'unknown']);
        $fail($context['error'] ?? 'Could not build CourierIT1 label payload.');
    }

    $payload = $context['payload'];
    $rate_id = trim((string)($arg_rate ?? ''));
    $selected_rate = null;
    if ($rate_id === '' || $rate_id === 'none') {
        $quote = courierit1_request_json('POST', 'Consignments/calculate', $payload);
        if (empty($quote['success'])) {
            $fail(afri_extract_carrier_error($quote, (string)($quote['_raw'] ?? '')));
        }
        $selected_rate = is_array($quote['result']['rates'][0] ?? null) ? $quote['result']['rates'][0] : null;
        $rate_id = (string)($selected_rate['id'] ?? '');
    }
    if ($rate_id === '') {
        $fail('CourierIT1 did not return a usable shipping rate.');
    }
    if (!$selected_rate) {
        $quote = courierit1_request_json('POST', 'Consignments/calculate', $payload);
        foreach (($quote['result']['rates'] ?? []) as $rate) {
            if (is_array($rate) && (string)($rate['id'] ?? '') === $rate_id) {
                $selected_rate = $rate;
                break;
            }
        }
    }
    if (is_array($selected_rate)) {
        $payload['shippingDescription'] = trim((string)($selected_rate['name'] ?? $payload['shippingDescription']));
        $payload['shippingMethod'] = $payload['shippingDescription'];
        if (isset($selected_rate['parcels'][0]['markupRate'])) {
            $payload['consignmentParcels'][0]['markupRate'] = (float)$selected_rate['parcels'][0]['markupRate'];
        }
    }

    $create_path = 'Consignments/create/' . str_replace(' ', '%20', $rate_id);
    $create = courierit1_request_json('POST', $create_path, $payload);
    Logger::info('courierit1.print_label', 'create_response', [
        'order' => $shopify_num,
        'http' => $create['_http'] ?? 0,
        'success' => !empty($create['success']) ? '1' : '0',
        'message' => $create['message'] ?? '',
    ]);
    if (empty($create['success'])) {
        $fail(afri_extract_carrier_error($create, (string)($create['_raw'] ?? '')));
    }

    $courier_order_id = $context['order']['id'] ?? '';
    $print_client_result = '';
    if ($courier_order_id !== '') {
        $print_request = courierit1_label_print_request($courier_order_id);
        $print_client_result = courierit1_print_client_result($print_request['decoded'] ?? null);
        if ($print_client_result === '') $print_client_result = courierit1_print_client_result($print_request['_raw'] ?? '');
        Logger::info('courierit1.print_label', 'label_print_request', [
            'order_id' => $courier_order_id,
            'http' => $print_request['_http'] ?? 0,
            'success' => !empty($print_request['success']) ? '1' : '0',
            'result' => $print_client_result,
            'raw_length' => strlen((string)($print_request['_raw'] ?? '')),
        ]);
    }
    $label_pdf_url = courierit1_label_pdf_url($courier_order_id);
    if ($shopify_num !== '' && $label_pdf_url !== '') {
        $label_consignment_id = is_numeric($courier_order_id) ? (int)$courier_order_id : 0;
        $label_stmt = $db->prepare(
            "INSERT INTO pp_packie_cache (shopify_order_number, label_consignment_id, label_pdf_url, packie_status)
             VALUES (?, ?, ?, 'PRINTED')
             ON DUPLICATE KEY UPDATE
                 label_consignment_id = VALUES(label_consignment_id),
                 label_pdf_url = VALUES(label_pdf_url),
                 packie_status = 'PRINTED'"
        );
        $label_stmt->bind_param('sis', $shopify_num, $label_consignment_id, $label_pdf_url);
        $label_stmt->execute();
    }

    if (function_exists('ecommerce_update_order_tags') && $order_id !== '') {
        $staff = (string)($arg_staff ?? 'Staff');
        $updated_tags = $tags ? "$tags, Packed, Packed by $staff" : "Packed, Packed by $staff";
        ecommerce_update_order_tags($order_id, $updated_tags);
    }

    echo json_encode([
        'success' => true,
        'order_id' => $order_id,
        'order_name' => $order_name,
        'shopify_num' => $shopify_num,
        'provider' => 'CourierIT1',
        'label_pdf_url' => $label_pdf_url,
        'print_client_result' => $print_client_result,
    ]) . "\n";
    exit;
}
