<?php
/**
 * wa_api.php  —  outbound message library.
 *
 * Drop-in replacement for the earlier version. Same config constants,
 * same logging. wa_send_raw() is now the single transport; every
 * message type is just a different payload built on top of it.
 */

require_once __DIR__ . '/config.php';

// =====================================================================
// TRANSPORT
// =====================================================================

/**
 * Sends any Cloud-API-shaped payload. All helpers below funnel through here.
 *
 * @return array{ok:bool, http:int, message_id:?string, body:string}
 */
function wa_send_raw(array $payload): array
{
    if (WA_API_MODE !== 'cloud') {
        return ['ok' => false, 'http' => 0, 'message_id' => null,
                'body' => 'Rich message types require WA_API_MODE = cloud'];
    }

    $url  = rtrim(WA_API_URL, '/');
    $body = json_encode($payload, JSON_UNESCAPED_UNICODE);

    $headers = [
        'Content-Type: application/json',
        'Accept: application/json',
        'Authorization: Bearer ' . trim(WA_API_KEY),
    ];

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $body,
        CURLOPT_HTTPHEADER     => $headers,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 20,
        CURLOPT_CONNECTTIMEOUT => 10,
    ]);

    $response = curl_exec($ch);
    $http     = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curlErr  = curl_error($ch);
    curl_close($ch);

    if ($response === false) {
        wa_log_api($url, wa_redact($headers) . "\n" . $body, 0, $curlErr);
        return ['ok' => false, 'http' => 0, 'message_id' => null, 'body' => $curlErr];
    }

    wa_log_api($url, wa_redact($headers) . "\n" . $body, $http, $response);

    $decoded = json_decode($response, true);
    $msgId   = is_array($decoded)
        ? ($decoded['messages'][0]['id'] ?? $decoded['message_id'] ?? $decoded['id'] ?? null)
        : null;

    $ok = ($http >= 200 && $http < 300);

    if ($ok) {
        try {
            db()->prepare(
                "INSERT INTO wa_messages
                   (wa_message_id, direction, wa_to, msg_type, body, status, event_time)
                 VALUES (?, 'out', ?, ?, ?, 'submitted', NOW())
                 ON DUPLICATE KEY UPDATE body = VALUES(body)"
            )->execute([
                $msgId ?: 'local_' . uniqid(),
                $payload['to'] ?? '',
                $payload['type'] ?? 'text',
                mb_substr(json_encode($payload[$payload['type'] ?? 'text'] ?? [], JSON_UNESCAPED_UNICODE), 0, 2000),
            ]);
        } catch (Throwable $e) {
            error_log('wa_send_raw db log failed: ' . $e->getMessage());
        }
    }

    return ['ok' => $ok, 'http' => $http, 'message_id' => $msgId, 'body' => $response];
}

function wa_envelope(string $to, string $type, array $content): array
{
    return [
        'messaging_product' => 'whatsapp',
        'recipient_type'    => 'individual',
        'to'                => preg_replace('/\D+/', '', $to),
        'type'              => $type,
        $type               => $content,
    ];
}

/** WhatsApp silently rejects over-length fields, so clip them. */
function wa_trim(string $s, int $max): string
{
    $s = trim($s);
    return mb_strlen($s) > $max ? mb_substr($s, 0, $max - 1) . '…' : $s;
}


// =====================================================================
// 1. PLAIN TEXT
// =====================================================================

function wa_send_text(string $to, string $text, bool $previewUrl = false): array
{
    return wa_send_raw(wa_envelope($to, 'text', [
        'preview_url' => $previewUrl,
        'body'        => wa_trim($text, 4096),
    ]));
}


// =====================================================================
// 2. LOCATION  —  "here is our address" as a map pin
// =====================================================================

function wa_send_location(
    string $to,
    float  $latitude,
    float  $longitude,
    string $name    = '',
    string $address = ''
): array {
    $content = ['latitude' => $latitude, 'longitude' => $longitude];
    if ($name !== '')    $content['name']    = wa_trim($name, 1000);
    if ($address !== '') $content['address'] = wa_trim($address, 1000);

    return wa_send_raw(wa_envelope($to, 'location', $content));
}


// =====================================================================
// 3. REPLY BUTTONS  —  up to 3 quick choices
// =====================================================================

/**
 * @param array $buttons  ['id' => 'Label', ...]  max 3, labels max 20 chars
 */
function wa_send_buttons(
    string $to,
    string $bodyText,
    array  $buttons,
    string $header = '',
    string $footer = ''
): array {
    $rows = [];
    foreach (array_slice($buttons, 0, 3, true) as $id => $label) {
        $rows[] = [
            'type'  => 'reply',
            'reply' => ['id' => (string) $id, 'title' => wa_trim((string) $label, 20)],
        ];
    }

    $interactive = [
        'type'   => 'button',
        'body'   => ['text' => wa_trim($bodyText, 1024)],
        'action' => ['buttons' => $rows],
    ];
    if ($header !== '') $interactive['header'] = ['type' => 'text', 'text' => wa_trim($header, 60)];
    if ($footer !== '') $interactive['footer'] = ['text' => wa_trim($footer, 60)];

    return wa_send_raw(wa_envelope($to, 'interactive', $interactive));
}


// =====================================================================
// 4. INTERACTIVE LIST  —  your own product/service menu, no catalog
// =====================================================================

/**
 * @param array $sections  [
 *     'Section title' => [
 *         ['id' => 'sku_1', 'title' => 'Cotton Shirt', 'description' => '₹499'],
 *         ...
 *     ],
 * ]
 *
 * HARD LIMIT: 10 rows TOTAL across all sections. Meta rejects the whole
 * message if you exceed it — paginate with a "More" row if you have more.
 */
function wa_send_list(
    string $to,
    string $bodyText,
    string $buttonLabel,
    array  $sections,
    string $header = '',
    string $footer = ''
): array {
    $built = [];
    $count = 0;

    foreach ($sections as $sectionTitle => $rows) {
        $builtRows = [];
        foreach ($rows as $row) {
            if ($count >= 10) break 2;
            $r = [
                'id'    => wa_trim((string) ($row['id'] ?? 'row_' . $count), 200),
                'title' => wa_trim((string) ($row['title'] ?? ''), 24),
            ];
            if (!empty($row['description'])) {
                $r['description'] = wa_trim((string) $row['description'], 72);
            }
            $builtRows[] = $r;
            $count++;
        }
        if ($builtRows) {
            $built[] = ['title' => wa_trim((string) $sectionTitle, 24), 'rows' => $builtRows];
        }
    }

    $interactive = [
        'type'   => 'list',
        'body'   => ['text' => wa_trim($bodyText, 1024)],
        'action' => ['button' => wa_trim($buttonLabel, 20), 'sections' => $built],
    ];
    if ($header !== '') $interactive['header'] = ['type' => 'text', 'text' => wa_trim($header, 60)];
    if ($footer !== '') $interactive['footer'] = ['text' => wa_trim($footer, 60)];

    return wa_send_raw(wa_envelope($to, 'interactive', $interactive));
}


// =====================================================================
// 5. CATALOG PRODUCTS  —  requires a Meta Commerce catalog on your WABA
// =====================================================================

/** One product card with image, price and an "Add to cart" flow. */
function wa_send_product(string $to, string $retailerId, string $bodyText = '', string $footer = ''): array
{
    $interactive = [
        'type'   => 'product',
        'action' => [
            'catalog_id'          => WA_CATALOG_ID,
            'product_retailer_id' => $retailerId,
        ],
    ];
    if ($bodyText !== '') $interactive['body']   = ['text' => wa_trim($bodyText, 1024)];
    if ($footer !== '')   $interactive['footer'] = ['text' => wa_trim($footer, 60)];

    return wa_send_raw(wa_envelope($to, 'interactive', $interactive));
}

/**
 * Multi-product message, grouped into sections.
 *
 * @param array $sections ['Section title' => ['SKU1', 'SKU2'], ...]
 *                        Max 30 products total, max 10 sections.
 */
function wa_send_product_list(
    string $to,
    string $headerText,
    string $bodyText,
    array  $sections,
    string $footer = ''
): array {
    $built = [];
    foreach ($sections as $title => $skus) {
        $items = [];
        foreach ($skus as $sku) {
            $items[] = ['product_retailer_id' => (string) $sku];
        }
        $built[] = ['title' => wa_trim((string) $title, 24), 'product_items' => $items];
    }

    $interactive = [
        'type'   => 'product_list',
        'header' => ['type' => 'text', 'text' => wa_trim($headerText, 60)],
        'body'   => ['text' => wa_trim($bodyText, 1024)],
        'action' => ['catalog_id' => WA_CATALOG_ID, 'sections' => $built],
    ];
    if ($footer !== '') $interactive['footer'] = ['text' => wa_trim($footer, 60)];

    return wa_send_raw(wa_envelope($to, 'interactive', $interactive));
}


// =====================================================================
// Logging helpers
// =====================================================================

function wa_redact(array $headers): string
{
    $safe = [];
    foreach ($headers as $h) {
        $safe[] = preg_replace('/(Bearer\s+|:\s*)\S{6}\S*/i', '$1$2******', $h);
    }
    return implode(' | ', $safe);
}

function wa_log_api(string $url, ?string $request, int $http, string $response): void
{
    try {
        db()->prepare(
            "INSERT INTO wa_api_log (url, request, http_code, response) VALUES (?, ?, ?, ?)"
        )->execute([$url, $request, $http, $response]);
    } catch (Throwable $e) {
        error_log('wa_log_api failed: ' . $e->getMessage());
    }
}
