<?php
/**
 * Plisio integration helpers.
 *
 * IMPORTANT:
 * This file is used by both Mini App endpoints and the Telegram bot webhook.
 * Do NOT include public/mini_app/api/config.php here, because that file declares
 * Mini App-only helper functions such as ensureUser(). Including it from bot.php
 * causes a fatal "Cannot redeclare ensureUser()" and breaks the Telegram bot.
 */
$__coreConfig = dirname(__DIR__, 3) . '/src/config.php';
if (is_file($__coreConfig)) {
    require_once $__coreConfig;
}

if (!isset($pdo) || !($pdo instanceof PDO)) {
    $pdo = db();
}

function plisio_enabled(): bool {
    return getSetting('plisio_enabled','0') === '1' && trim((string)getSetting('plisio_api_key','')) !== '';
}

function plisio_api_key(): string { return trim((string)getSetting('plisio_api_key','')); }

function plisio_callback_url(): string {
    $mini = rtrim((string)(defined('MINIAPP_URL') ? MINIAPP_URL : ''), '/');
    if ($mini !== '') return $mini . '/api/plisio_webhook.php';
    $https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
    return $https . '://' . $host . '/telegram-bot/public/mini_app/api/plisio_webhook.php';
}

function plisio_verify_callback(array $post): bool {
    $key = plisio_api_key();
    if ($key === '' || empty($post['verify_hash'])) return false;
    $verifyHash = (string)$post['verify_hash'];
    unset($post['verify_hash']);
    ksort($post);
    if (isset($post['expire_utc'])) $post['expire_utc'] = (string)$post['expire_utc'];
    if (isset($post['tx_urls'])) $post['tx_urls'] = html_entity_decode((string)$post['tx_urls'], ENT_QUOTES | ENT_HTML5, 'UTF-8');
    $check = hash_hmac('sha1', serialize($post), $key);
    return hash_equals($check, $verifyHash);
}


function plisio_normalize_asset(string $asset): string {
    $a = strtoupper(trim($asset));
    if (in_array($a, ['USDT','TETHER','USDT_TRC20','USDT_TRX','USDT_BSC'], true)) return 'USDT';
    if (in_array($a, ['TRX','TRON'], true)) return 'TRX';
    return '';
}

function plisio_psys_for_asset(string $asset): string {
    $asset = plisio_normalize_asset($asset);
    $configured = strtoupper(trim((string)getSetting('plisio_currencies','USDT_BSC,TRX')));
    $list = array_values(array_filter(array_map('trim', explode(',', preg_replace('/[^A-Z0-9_,]/', '', $configured)))));
    if ($asset === 'TRX') return in_array('TRX', $list, true) ? 'TRX' : 'TRX';
    if ($asset === 'USDT') {
        foreach (['USDT_BSC','USDT_TRX','USDT_POLYGON','USDT_ETH'] as $c) {
            if (in_array($c, $list, true)) return $c;
        }
        return 'USDT_BSC';
    }
    return $configured;
}

function plisio_source_amount_usd(int $amountToman, string $asset=''): array {
    $rate = max(1, (float)getSetting('plisio_usd_rate_toman','60000'));
    $raw = max(0.01, $amountToman / $rate);
    $assetNorm = plisio_normalize_asset($asset);

    // Plisio may reject small stablecoin invoices on some networks, especially USDT_TRX. In production this used to
    // surface as a raw API error and broke the customer flow. For gateway
    // payments we automatically raise the invoice source amount to the minimum
    // accepted by Plisio, while keeping the internal order/wallet amount intact.
    // Manual crypto payments still show the exact amount based on admin rates.
    $min = max(5.01, (float)getSetting('plisio_min_invoice_usd','5.01'));
    $charged = $raw;
    $minimumApplied = false;
    if ($assetNorm === 'USDT' && $charged < $min) {
        $charged = $min;
        $minimumApplied = true;
    }

    return [
        'raw' => number_format($raw, 2, '.', ''),
        'charged' => number_format($charged, 2, '.', ''),
        'minimum_applied' => $minimumApplied,
        'minimum' => number_format($min, 2, '.', ''),
        'rate' => $rate,
    ];
}

function plisio_toman_to_usd(int $amountToman): string {
    $q = plisio_source_amount_usd($amountToman, '');
    return $q['charged'];
}

function plisio_create_invoice(string $orderNumber, string $orderName, int $amountToman, string $type='order', string $asset=''): array {
    $apiKey = plisio_api_key();
    if ($apiKey === '') throw new RuntimeException('Plisio API Key تنظیم نشده است');
    $asset = plisio_normalize_asset($asset);
    $sourceQuote = plisio_source_amount_usd($amountToman, $asset);
    $params = [
        'api_key' => $apiKey,
        'order_number' => $orderNumber,
        'order_name' => $orderName,
        'source_currency' => 'USD',
        'source_amount' => $sourceQuote['charged'],
        'callback_url' => plisio_callback_url(),
        'success_callback_url' => rtrim((string)(defined('MINIAPP_URL') ? MINIAPP_URL : ''), '/') ?: 'https://gemacc.ir/telegram-bot/public/mini_app/',
        'fail_callback_url' => rtrim((string)(defined('MINIAPP_URL') ? MINIAPP_URL : ''), '/') ?: 'https://gemacc.ir/telegram-bot/public/mini_app/',
        'description' => $orderName,
    ];
    $allowAllGatewayCurrencies = getSetting('plisio_allow_all_currencies','1') === '1';
    if (!$allowAllGatewayCurrencies) {
        $currencies = $asset !== '' ? plisio_psys_for_asset($asset) : strtoupper(trim((string)getSetting('plisio_currencies','')));
        $currencies = preg_replace('/[^A-Z0-9_,]/', '', $currencies);
        if ($currencies !== '') $params['allowed_psys_cids'] = $currencies;
    }
    $url = 'https://api.plisio.net/api/v1/invoices/new?' . http_build_query($params);
    $ch = curl_init($url);
    curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>20, CURLOPT_CONNECTTIMEOUT=>10, CURLOPT_SSL_VERIFYPEER=>true]);
    $body = (string)curl_exec($ch);
    $err = curl_error($ch);
    $http = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if ($body === '' && $err !== '') throw new RuntimeException('خطای اتصال به Plisio: ' . $err);
    $json = json_decode($body, true);
    if (!is_array($json) || ($json['status'] ?? '') !== 'success') {
        $msg = $json['data']['message'] ?? $json['message'] ?? ('HTTP ' . $http);
        if (is_array($msg)) $msg = implode(' | ', array_map('strval', $msg));
        if (stripos((string)$msg, 'minimal amount') !== false || stripos((string)$msg, 'minimum') !== false) {
            $msg .= ' | مبلغ این سفارش از حداقل مجاز Plisio کمتر است. اگر این خطا را می‌بینید، مقدار plisisio_min_invoice_usd یا نرخ دلار Plisio را بررسی کنید.';
        }
        throw new RuntimeException('خطای Plisio: ' . $msg);
    }
    $data = $json['data'] ?? [];
    if (empty($data['invoice_url'])) throw new RuntimeException('Plisio invoice_url برنگرداند');
    return ['raw'=>$json, 'txn_id'=>(string)($data['txn_id'] ?? ''), 'invoice_url'=>(string)$data['invoice_url'], 'crypto_amount'=>(string)($data['invoice_total_sum'] ?? $data['amount'] ?? ''), 'currency'=>(string)($data['currency'] ?? $data['psys_cid'] ?? ''), 'source_amount_raw'=>$sourceQuote['raw'], 'source_amount_charged'=>$sourceQuote['charged'], 'minimum_applied'=>$sourceQuote['minimum_applied'], 'minimum_source_amount'=>$sourceQuote['minimum']];
}
