<?php

/**
 * @return array{ok: bool, status: int, body: array|null, raw: string}
 */
function hubspot_json_request(string $method, string $path, ?array $body): array
{
    $token = defined('HUBSPOT_PRIVATE_APP_TOKEN') ? HUBSPOT_PRIVATE_APP_TOKEN : '';
    $url = 'https://api.hubapi.com' . $path;

    $headers = [
        'Authorization: Bearer ' . $token,
        'Content-Type: application/json',
    ];

    $ch = curl_init($url);
    $opts = [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_TIMEOUT => 45,
        CURLOPT_CUSTOMREQUEST => strtoupper($method),
    ];
    if ($body !== null) {
        $opts[CURLOPT_POSTFIELDS] = json_encode($body);
    }
    curl_setopt_array($ch, $opts);
    $raw = curl_exec($ch);
    $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    $decoded = null;
    if (is_string($raw) && $raw !== '') {
        $decoded = json_decode($raw, true);
    }

    return [
        'ok' => $status >= 200 && $status < 300,
        'status' => $status,
        'body' => is_array($decoded) ? $decoded : null,
        'raw' => is_string($raw) ? $raw : '',
    ];
}

/**
 * @return string|null Existing deal ID, or null
 */
function hubspot_find_deal_id_by_shopify_order(string $shopifyOrderId): ?string
{
    $prop = HUBSPOT_DEAL_PROPERTY_SHOPIFY_ORDER_ID;
    $payload = [
        'filterGroups' => [
            [
                'filters' => [
                    [
                        'propertyName' => $prop,
                        'operator' => 'EQ',
                        'value' => $shopifyOrderId,
                    ],
                ],
            ],
        ],
        'properties' => ['dealname', $prop],
        'limit' => 1,
    ];

    $res = hubspot_json_request('POST', '/crm/v3/objects/deals/search', $payload);
    if (!$res['ok'] || !is_array($res['body'])) {
        return null;
    }
    $results = $res['body']['results'] ?? [];
    if (!is_array($results) || $results === []) {
        return null;
    }
    $id = $results[0]['id'] ?? null;
    return $id !== null ? (string) $id : null;
}

/**
 * @param array $order Shopify order JSON (decoded)
 * @param string|null $dealStageId Optional override for the dealstage internal ID.
 * @return array{ok: bool, status: int, deal_id?: string, error?: string}
 */
function hubspot_create_deal_from_shopify_order(array $order, ?string $dealStageId = null): array
{
    $orderId = isset($order['id']) ? (string) $order['id'] : '';
    $name = isset($order['name']) ? (string) $order['name'] : ('Order ' . $orderId);
    $amountRaw = $order['total_price'] ?? $order['current_total_price'] ?? '0';
    $amount = is_numeric($amountRaw) ? (string) $amountRaw : '0';

    $resolvedStageId = $dealStageId !== null && $dealStageId !== '' ? (string) $dealStageId : HUBSPOT_DEALSTAGE_ID;
    $properties = [
        'dealname' => 'Shopify ' . $name,
        'amount' => $amount,
        'pipeline' => HUBSPOT_PIPELINE_ID,
        'dealstage' => $resolvedStageId,
        HUBSPOT_DEAL_PROPERTY_SHOPIFY_ORDER_ID => $orderId,
    ];

    // Multi-line text field in HubSpot to store all product names from this Shopify order.
    // Format: "#1, Product A" newline "#2, Product B" ...
    $lineItems = $order['line_items'] ?? [];
    $productNamesText = '';
    if (is_array($lineItems) && $lineItems !== []) {
        $names = [];
        $i = 1;
        foreach ($lineItems as $item) {
            if (!is_array($item)) {
                continue;
            }

            $title = trim((string) ($item['title'] ?? $item['name'] ?? ''));
            if ($title === '') {
                $sku = trim((string) ($item['sku'] ?? ''));
                if ($sku !== '') {
                    $title = 'SKU ' . $sku;
                } else {
                    $pid = $item['product_id'] ?? '';
                    if ($pid !== '') {
                        $title = 'Product ' . (string) $pid;
                    }
                }
            }

            if ($title !== '') {
                $names[] = '#' . $i . ', ' . $title;
            }
            $i++;
        }
        $productNamesText = implode(PHP_EOL, $names);
    }
    if ($productNamesText !== '') {
        $properties[HUBSPOT_DEAL_PROPERTY_PRODUCT_NAMES] = $productNamesText;
    }

    // Helpful for closed / completed stages
    $properties['closedate'] = (new DateTimeImmutable('now', new DateTimeZone('UTC')))
        ->format('Y-m-d\TH:i:s.000\Z');

    $res = hubspot_json_request('POST', '/crm/v3/objects/deals', ['properties' => $properties]);
    if ($res['ok'] && is_array($res['body']) && isset($res['body']['id'])) {
        return ['ok' => true, 'status' => $res['status'], 'deal_id' => (string) $res['body']['id']];
    }

    $msg = $res['body']['message'] ?? $res['raw'];
    return ['ok' => false, 'status' => $res['status'], 'error' => is_string($msg) ? $msg : 'HubSpot error'];
}

/**
 * Patch deal custom properties (e.g. PandaDoc signed document URL).
 *
 * @param array<string, string> $properties HubSpot internal property name => value
 * @return array{ok: bool, status: int, error?: string}
 */
function hubspot_update_deal_properties(string $dealId, array $properties): array
{
    if ($dealId === '' || $properties === []) {
        return ['ok' => false, 'status' => 400, 'error' => 'Missing deal id or properties'];
    }

    $res = hubspot_json_request('PATCH', '/crm/v3/objects/deals/' . rawurlencode($dealId), [
        'properties' => $properties,
    ]);

    if ($res['ok']) {
        return ['ok' => true, 'status' => $res['status']];
    }

    $msg = $res['body']['message'] ?? ($res['body']['errors'][0]['message'] ?? $res['raw']);
    return [
        'ok' => false,
        'status' => $res['status'],
        'error' => is_string($msg) ? $msg : 'HubSpot PATCH deal failed',
    ];
}

/**
 * @return string|null HubSpot Order record id, or null
 */
function hubspot_find_order_id_by_shopify_order(string $shopifyOrderId): ?string
{
    if (!defined('HUBSPOT_ORDER_PROPERTY_SHOPIFY_ORDER_ID')) {
        return null;
    }
    $prop = HUBSPOT_ORDER_PROPERTY_SHOPIFY_ORDER_ID;
    if ($prop === '') {
        return null;
    }

    $payload = [
        'filterGroups' => [
            [
                'filters' => [
                    [
                        'propertyName' => $prop,
                        'operator' => 'EQ',
                        'value' => $shopifyOrderId,
                    ],
                ],
            ],
        ],
        'properties' => ['hs_order_name', $prop],
        'limit' => 1,
    ];

    $res = hubspot_json_request('POST', '/crm/v3/objects/orders/search', $payload);
    if (!$res['ok'] || !is_array($res['body'])) {
        return null;
    }
    $results = $res['body']['results'] ?? [];
    if (!is_array($results) || $results === []) {
        return null;
    }
    $id = $results[0]['id'] ?? null;
    return $id !== null ? (string) $id : null;
}



/**
 * Find a HubSpot Order by Shopify order id and return properties.
 *
 * @param string[] $propertiesToFetch
 * @return array{id: string, properties: array<string, mixed>}|null
 */
function hubspot_find_order_by_shopify_order(string $shopifyOrderId, array $propertiesToFetch = []): ?array
{
    if (!defined('HUBSPOT_ORDER_PROPERTY_SHOPIFY_ORDER_ID')) {
        return null;
    }
    $prop = HUBSPOT_ORDER_PROPERTY_SHOPIFY_ORDER_ID;
    if ($prop === '') {
        return null;
    }

    $properties = array_values(array_unique(array_filter(array_merge(['hs_order_name', $prop], $propertiesToFetch), static function ($v) {
        return is_string($v) && trim($v) !== '';
    })));

    $payload = [
        'filterGroups' => [
            [
                'filters' => [
                    [
                        'propertyName' => $prop,
                        'operator' => 'EQ',
                        'value' => $shopifyOrderId,
                    ],
                ],
            ],
        ],
        'properties' => $properties,
        'limit' => 1,
    ];

    $res = hubspot_json_request('POST', '/crm/v3/objects/orders/search', $payload);
    if (!$res['ok'] || !is_array($res['body'])) {
        return null;
    }
    $results = $res['body']['results'] ?? [];
    if (!is_array($results) || $results === []) {
        return null;
    }
    $id = $results[0]['id'] ?? null;
    if ($id === null || (string) $id === '') {
        return null;
    }
    $props = $results[0]['properties'] ?? [];
    return [
        'id' => (string) $id,
        'properties' => is_array($props) ? $props : [],
    ];
}


/**
 * Patch HubSpot Order properties (e.g. PandaDoc signed document URL).
 *
 * @param array<string, string> $properties HubSpot internal property name => value
 * @return array{ok: bool, status: int, error?: string}
 */
function hubspot_update_order_properties(string $orderId, array $properties): array
{
    if ($orderId === '' || $properties === []) {
        return ['ok' => false, 'status' => 400, 'error' => 'Missing order id or properties'];
    }

    $res = hubspot_json_request('PATCH', '/crm/v3/objects/orders/' . rawurlencode($orderId), [
        'properties' => $properties,
    ]);

    if ($res['ok']) {
        return ['ok' => true, 'status' => $res['status']];
    }

    $msg = $res['body']['message'] ?? ($res['body']['errors'][0]['message'] ?? $res['raw']);
    return [
        'ok' => false,
        'status' => $res['status'],
        'error' => is_string($msg) ? $msg : 'HubSpot PATCH order failed',
    ];
}
