<?php
declare(strict_types=1);

if (is_readable(__DIR__ . '/config.php')) {
    require_once __DIR__ . '/config.php';
}

function mocker_telegram_bot_token(): string
{
    return defined('SITE_TELEGRAM_BOT_TOKEN') ? trim((string) SITE_TELEGRAM_BOT_TOKEN) : '';
}

function mocker_telegram_bot_username(): string
{
    $u = defined('SITE_TELEGRAM_BOT_USERNAME') ? trim((string) SITE_TELEGRAM_BOT_USERNAME) : '';
    return ltrim($u, '@');
}

function mocker_telegram_webhook_secret(): string
{
    return defined('SITE_TELEGRAM_WEBHOOK_SECRET') ? trim((string) SITE_TELEGRAM_WEBHOOK_SECRET) : '';
}

function mocker_telegram_is_configured(): bool
{
    return mocker_telegram_bot_token() !== '' && mocker_telegram_bot_username() !== '';
}

/** Domain for Telegram Login Widget (BotFather → /setdomain). */
function mocker_telegram_widget_domain(): string
{
    $host = strtolower(trim((string) ($_SERVER['HTTP_HOST'] ?? '')));
    if ($host === '') {
        return '';
    }
    if (preg_match('#^(\[[\da-f:]+\]|[^:]+)(:\d+)?$#iu', $host, $m)) {
        $name = $m[1];
        $port = $m[2] ?? '';
        if ($name === 'localhost' || $name === '127.0.0.1' || filter_var($name, FILTER_VALIDATE_IP)) {
            return $name . $port;
        }

        return $name;
    }

    return $host;
}

function mocker_telegram_hash_token(string $token): string
{
    return hash('sha256', $token);
}

function mocker_telegram_verify_login_widget(array $data): bool
{
    $token = mocker_telegram_bot_token();
    if ($token === '' || !isset($data['hash']) || !is_string($data['hash'])) {
        return false;
    }

    $checkHash = $data['hash'];
    unset($data['hash']);

    $pairs = [];
    foreach ($data as $key => $value) {
        if (!is_scalar($value) || $value === '') {
            continue;
        }
        $pairs[] = $key . '=' . $value;
    }
    sort($pairs, SORT_STRING);
    $dataCheckString = implode("\n", $pairs);

    $secretKey = hash('sha256', $token, true);
    $computed = hash_hmac('sha256', $dataCheckString, $secretKey);
    if (!hash_equals($computed, $checkHash)) {
        return false;
    }

    $authDate = isset($data['auth_date']) ? (int) $data['auth_date'] : 0;

    return $authDate > 0 && (time() - $authDate) <= 86400;
}

/**
 * Telegram Mini App (WebApp) initData imzasını doğrular.
 * Spec: https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-app
 *
 * secret_key = HMAC_SHA256("WebAppData", bot_token)
 * data_check_string = key=value satırları, hash hariç, key'e göre alfabetik sıralı, "\n" ile ayrılmış.
 *
 * Başarılıysa parse edilmiş alanları döner (user JSON çözülmüş, sayısal alanlar int'e dönmüş);
 * başarısızsa null. $maxAgeSeconds: auth_date'in maksimum yaşı (default 1 gün, 0 = limit yok).
 */
function mocker_telegram_verify_webapp_init_data(string $initData, int $maxAgeSeconds = 86400): ?array
{
    $token = mocker_telegram_bot_token();
    if ($token === '' || $initData === '') {
        return null;
    }

    $pairs = [];
    $hash = null;
    foreach (explode('&', $initData) as $segment) {
        if ($segment === '') {
            continue;
        }
        $eq = strpos($segment, '=');
        if ($eq === false) {
            continue;
        }
        $rawKey = substr($segment, 0, $eq);
        $rawVal = substr($segment, $eq + 1);
        $key = urldecode($rawKey);
        $val = urldecode($rawVal);
        if ($key === 'hash') {
            $hash = $val;
            continue;
        }
        $pairs[$key] = $val;
    }

    if ($hash === null || $hash === '' || $pairs === []) {
        return null;
    }

    ksort($pairs, SORT_STRING);
    $lines = [];
    foreach ($pairs as $k => $v) {
        $lines[] = $k . '=' . $v;
    }
    $dataCheckString = implode("\n", $lines);

    $secretKey = hash_hmac('sha256', $token, 'WebAppData', true);
    $computed = hash_hmac('sha256', $dataCheckString, $secretKey);

    if (!hash_equals($computed, strtolower($hash))) {
        return null;
    }

    $authDate = isset($pairs['auth_date']) ? (int) $pairs['auth_date'] : 0;
    if ($authDate <= 0) {
        return null;
    }
    if ($maxAgeSeconds > 0 && (time() - $authDate) > $maxAgeSeconds) {
        return null;
    }

    $user = null;
    if (isset($pairs['user']) && is_string($pairs['user']) && $pairs['user'] !== '') {
        $decoded = json_decode($pairs['user'], true);
        if (is_array($decoded)) {
            $user = $decoded;
        }
    }

    return [
        'auth_date' => $authDate,
        'query_id' => isset($pairs['query_id']) ? (string) $pairs['query_id'] : '',
        'user' => $user,
        'start_param' => isset($pairs['start_param']) ? (string) $pairs['start_param'] : '',
        'chat_instance' => isset($pairs['chat_instance']) ? (string) $pairs['chat_instance'] : '',
        'chat_type' => isset($pairs['chat_type']) ? (string) $pairs['chat_type'] : '',
        'raw' => $pairs,
    ];
}

function mocker_telegram_parse_start_token(string $text): ?string
{
    $text = trim($text);
    if ($text === '' || !preg_match('#^/start(?:@\S+)?(?:\s|$)#iu', $text)) {
        return null;
    }
    if (preg_match('#^/start(?:@\S+)?\s+(\S+)#iu', $text, $m)) {
        return trim((string) $m[1]);
    }

    return '';
}

function mocker_telegram_normalize_verify_token(string $token): ?string
{
    $token = trim($token);
    if ($token === '') {
        return null;
    }
    if (preg_match('/^([a-f0-9]{32})$/i', $token, $m)) {
        return strtolower($m[1]);
    }

    return null;
}

function mocker_telegram_error_description(?array $j, ?string $curlErr = null): ?string
{
    if ($curlErr !== null && $curlErr !== '') {
        return $curlErr;
    }
    if (!is_array($j)) {
        return 'Telegram API yanıtı alınamadı (ağ veya SSL). Sunucunun api.telegram.org çıkışına izin verdiğini kontrol et.';
    }
    if (!empty($j['ok'])) {
        return null;
    }
    if (isset($j['description']) && is_string($j['description'])) {
        return $j['description'];
    }

    return 'Bilinmeyen Telegram API hatası.';
}

function mocker_telegram_normalize_chat_id($chatId): string
{
    if (is_int($chatId) || is_float($chatId)) {
        return (string) (int) $chatId;
    }
    $s = trim((string) $chatId);

    return $s === '' ? '0' : $s;
}

/** Projedeki cacert.pem yoluna döner; yoksa boş string. */
function mocker_telegram_curl_cacert_path(): string
{
    static $cached = null;
    if ($cached !== null) {
        return $cached;
    }
    $candidate = __DIR__ . DIRECTORY_SEPARATOR . 'cacert.pem';
    $cached = is_readable($candidate) ? $candidate : '';
    return $cached;
}

/** cURL handle'ına SSL CA bundle ekler (Windows/local PHP'lerde sertifika hatasını giderir). */
function mocker_telegram_curl_apply_ssl(\CurlHandle $ch): void
{
    $cacert = mocker_telegram_curl_cacert_path();
    if ($cacert !== '') {
        curl_setopt($ch, CURLOPT_CAINFO, $cacert);
    }
}

function mocker_telegram_api_post_json(string $method, array $payload): ?array
{
    $token = mocker_telegram_bot_token();
    if ($token === '') {
        return null;
    }
    if (isset($payload['chat_id'])) {
        $payload['chat_id'] = mocker_telegram_normalize_chat_id($payload['chat_id']);
    }
    $url = 'https://api.telegram.org/bot' . rawurlencode($token) . '/' . $method;
    $body = json_encode($payload, JSON_UNESCAPED_UNICODE);
    if ($body === false) {
        return null;
    }
    if (!function_exists('curl_init')) {
        $ctx = stream_context_create([
            'http' => [
                'method' => 'POST',
                'header' => "Content-Type: application/json; charset=utf-8\r\n",
                'content' => $body,
                'timeout' => 30,
            ],
        ]);
        $raw = @file_get_contents($url, false, $ctx);
        if ($raw === false) {
            return null;
        }

        return json_decode($raw, true) ?: null;
    }
    $ch = curl_init($url);
    if ($ch === false) {
        return null;
    }
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json; charset=utf-8']);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
    mocker_telegram_curl_apply_ssl($ch);
    $raw = curl_exec($ch);
    $curlErr = curl_error($ch);
    $curlNo = (int) curl_errno($ch);
    curl_close($ch);
    if ($raw === false || !is_string($raw)) {
        return [
            'ok' => false,
            'description' => $curlErr !== '' ? $curlErr : ('cURL #' . $curlNo),
        ];
    }

    return json_decode($raw, true) ?: null;
}

function mocker_telegram_api_post_multipart(string $method, array $fields): ?array
{
    $token = mocker_telegram_bot_token();
    if ($token === '' || !function_exists('curl_init')) {
        return null;
    }
    $url = 'https://api.telegram.org/bot' . rawurlencode($token) . '/' . $method;
    $ch = curl_init($url);
    if ($ch === false) {
        return null;
    }
    curl_setopt($ch, CURLOPT_POST, true);
    if (isset($fields['chat_id'])) {
        $fields['chat_id'] = mocker_telegram_normalize_chat_id($fields['chat_id']);
    }
    curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 60);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
    mocker_telegram_curl_apply_ssl($ch);
    $raw = curl_exec($ch);
    $curlErr = curl_error($ch);
    $curlNo = (int) curl_errno($ch);
    curl_close($ch);
    if ($raw === false || !is_string($raw)) {
        return [
            'ok' => false,
            'description' => $curlErr !== '' ? $curlErr : ('cURL #' . $curlNo),
        ];
    }

    return json_decode($raw, true) ?: null;
}

function mocker_telegram_extract_photo_file_id(?array $j): ?string
{
    if (!is_array($j) || empty($j['ok']) || !isset($j['result']) || !is_array($j['result'])) {
        return null;
    }
    $res = $j['result'];
    if (!isset($res['photo']) || !is_array($res['photo'])) {
        return null;
    }
    $photos = $res['photo'];
    if ($photos === []) {
        return null;
    }
    $last = end($photos);

    return isset($last['file_id']) ? (string) $last['file_id'] : null;
}

function mocker_telegram_extract_document_file_id(?array $j): ?string
{
    if (!is_array($j) || empty($j['ok']) || !isset($j['result']) || !is_array($j['result'])) {
        return null;
    }
    $doc = $j['result']['document'] ?? null;
    if (!is_array($doc) || !isset($doc['file_id'])) {
        return null;
    }

    return (string) $doc['file_id'];
}

function mocker_telegram_is_photo_dimension_error(?string $description): bool
{
    return $description !== null && stripos($description, 'PHOTO_INVALID_DIMENSIONS') !== false;
}

function mocker_telegram_send_document_ref(
    int|string $chatId,
    string $documentUrlOrFileId,
    string $caption = '',
    ?string $parseMode = null,
    ?array $replyMarkup = null
): array
{
    $payload = [
        'chat_id' => mocker_telegram_normalize_chat_id($chatId),
        'document' => $documentUrlOrFileId,
    ];
    if ($caption !== '') {
        $payload['caption'] = $caption;
    }
    if ($parseMode !== null && $parseMode !== '') {
        $payload['parse_mode'] = $parseMode;
    }
    if (is_array($replyMarkup) && $replyMarkup !== []) {
        $payload['reply_markup'] = $replyMarkup;
    }
    $j = mocker_telegram_api_post_json('sendDocument', $payload);
    if (!is_array($j) || empty($j['ok'])) {
        return ['ok' => false, 'file_id' => null, 'description' => mocker_telegram_error_description($j), 'is_document' => true];
    }

    return [
        'ok' => true,
        'file_id' => mocker_telegram_extract_document_file_id($j),
        'is_document' => true,
    ];
}

function mocker_telegram_send_document_upload(
    int|string $chatId,
    string $localPath,
    ?string $mime,
    string $caption = '',
    ?string $parseMode = null,
    ?array $replyMarkup = null
): array
{
    if (!is_readable($localPath) || !class_exists('CURLFile', false)) {
        return ['ok' => false, 'file_id' => null, 'description' => 'Dosya okunamadı veya CURLFile yok.'];
    }
    $mime = $mime !== null && $mime !== '' ? $mime : 'application/octet-stream';
    $fields = [
        'chat_id' => mocker_telegram_normalize_chat_id($chatId),
        'document' => new CURLFile($localPath, $mime, basename($localPath)),
    ];
    if ($caption !== '') {
        $fields['caption'] = $caption;
    }
    if ($parseMode !== null && $parseMode !== '') {
        $fields['parse_mode'] = $parseMode;
    }
    if (is_array($replyMarkup) && $replyMarkup !== []) {
        $fields['reply_markup'] = json_encode($replyMarkup, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    }
    $j = mocker_telegram_api_post_multipart('sendDocument', $fields);
    if (!is_array($j) || empty($j['ok'])) {
        return ['ok' => false, 'file_id' => null, 'description' => mocker_telegram_error_description($j), 'is_document' => true];
    }

    return [
        'ok' => true,
        'file_id' => mocker_telegram_extract_document_file_id($j),
        'is_document' => true,
    ];
}

function mocker_telegram_send_photo_ref(
    int|string $chatId,
    string $photoUrlOrFileId,
    string $caption = '',
    ?string $parseMode = null,
    ?array $replyMarkup = null
): array
{
    $payload = [
        'chat_id' => mocker_telegram_normalize_chat_id($chatId),
        'photo' => $photoUrlOrFileId,
    ];
    if ($caption !== '') {
        $payload['caption'] = $caption;
    }
    if ($parseMode !== null && $parseMode !== '') {
        $payload['parse_mode'] = $parseMode;
    }
    if (is_array($replyMarkup) && $replyMarkup !== []) {
        $payload['reply_markup'] = $replyMarkup;
    }
    $j = mocker_telegram_api_post_json('sendPhoto', $payload);
    if (is_array($j) && !empty($j['ok'])) {
        return [
            'ok' => true,
            'file_id' => mocker_telegram_extract_photo_file_id($j),
            'is_document' => false,
        ];
    }
    $desc = mocker_telegram_error_description($j);
    if (mocker_telegram_is_photo_dimension_error($desc)) {
        return mocker_telegram_send_document_ref($chatId, $photoUrlOrFileId, $caption, $parseMode, $replyMarkup);
    }

    return ['ok' => false, 'file_id' => null, 'description' => $desc];
}

function mocker_telegram_send_photo_upload(
    int|string $chatId,
    string $localPath,
    ?string $mime,
    string $caption = '',
    ?string $parseMode = null,
    ?array $replyMarkup = null
): array
{
    if (!is_readable($localPath) || !class_exists('CURLFile', false)) {
        return ['ok' => false, 'file_id' => null, 'description' => 'Dosya okunamadı veya CURLFile yok.'];
    }
    $mime = $mime !== null && $mime !== '' ? $mime : 'application/octet-stream';
    $fields = [
        'chat_id' => mocker_telegram_normalize_chat_id($chatId),
        'photo' => new CURLFile($localPath, $mime, basename($localPath)),
    ];
    if ($caption !== '') {
        $fields['caption'] = $caption;
    }
    if ($parseMode !== null && $parseMode !== '') {
        $fields['parse_mode'] = $parseMode;
    }
    if (is_array($replyMarkup) && $replyMarkup !== []) {
        $fields['reply_markup'] = json_encode($replyMarkup, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    }
    $j = mocker_telegram_api_post_multipart('sendPhoto', $fields);
    if (is_array($j) && !empty($j['ok'])) {
        return [
            'ok' => true,
            'file_id' => mocker_telegram_extract_photo_file_id($j),
            'is_document' => false,
        ];
    }
    $desc = mocker_telegram_error_description($j);
    if (mocker_telegram_is_photo_dimension_error($desc)) {
        return mocker_telegram_send_document_upload($chatId, $localPath, $mime, $caption, $parseMode, $replyMarkup);
    }

    return ['ok' => false, 'file_id' => null, 'description' => $desc];
}

function mocker_telegram_send_message(int $chatId, string $text): void
{
    mocker_telegram_send_message_result($chatId, $text, null);
}

function mocker_telegram_send_message_result(int|string $chatId, string $text, ?string $parseMode = null): bool
{
    $payload = [
        'chat_id' => mocker_telegram_normalize_chat_id($chatId),
        'text' => $text,
    ];
    if ($parseMode !== null && $parseMode !== '') {
        $payload['parse_mode'] = $parseMode;
    }
    $j = mocker_telegram_api_post_json('sendMessage', $payload);

    return is_array($j) && !empty($j['ok']);
}
