<?php
namespace EasyChat\Library\Messenger;

use CURLFile;
use EasyChat\Library\AttachmentPolicy;
use EasyChat\Library\Http\ExternalHttpClient;
use EasyChat\Library\MessageTextRenderer;
use EasyChat\Library\Http\ProxyPolicy;
use EasyChat\Library\ImageVariantService;

class TelegramProvider implements MessengerProviderInterface {

    const API_BASE = 'https://api.telegram.org/bot';
    const PROVIDER = 'telegram';

    private $registry;
    private $http;

    public function __construct($registry = null, ?ExternalHttpClient $http = null) {
        $this->registry = $registry;
        $this->http = $http ?: new ExternalHttpClient($registry);
    }

    public function providerCode(): string {
        return self::PROVIDER;
    }

    public function getBotInfo(string $token): array {
        return $this->apiJson('GET', '/getMe', $token);
    }

    public function syncWebhook(array $channel, string $token, string $webhook_url, string $secret): array {
        $me = $this->getBotInfo($token);
        if (empty($me['success'])) {
            return $me;
        }

        $body = [
            'url' => $webhook_url,
            'allowed_updates' => ['message', 'edited_message', 'callback_query'],
            'secret_token' => $secret,
        ];

        $sync = $this->apiJson('POST', '/setWebhook', $token, $body);
        if (empty($sync['success'])) {
            return $sync;
        }

        return [
            'success' => true,
            'bot' => [
                'user_id' => (string)($me['json']['result']['id'] ?? ''),
                'name' => (string)($me['json']['result']['first_name'] ?? ''),
                'username' => (string)($me['json']['result']['username'] ?? ''),
            ],
            'response' => $sync['json'],
            'http_code' => $sync['http_code'],
        ];
    }

    public function getWebhookInfo(string $token, array $options = []): array {
        return $this->apiJson('GET', '/getWebhookInfo', $token, null, $options);
    }

    public function deleteWebhook(string $token, array $options = []): array {
        return $this->apiJson('POST', '/deleteWebhook', $token, [
            'drop_pending_updates' => false,
        ], $options);
    }

    public function getUpdates(string $token, int $offset = 0, int $limit = 25, int $timeout = 0, array $options = []): array {
        $body = [
            'limit' => max(1, min(100, $limit)),
            'timeout' => max(0, min(10, $timeout)),
            'allowed_updates' => ['message', 'edited_message', 'callback_query'],
        ];
        if ($offset > 0) {
            $body['offset'] = $offset;
        }

        return $this->apiJson('POST', '/getUpdates', $token, $body, $options);
    }

    public function parseWebhook(array $payload): array {
        $update_type = 'message';
        $message = $payload['message'] ?? null;

        if (isset($payload['callback_query'])) {
            $update_type = 'callback_query';
            $message = $payload['callback_query']['message'] ?? null;
        } elseif (isset($payload['edited_message'])) {
            $update_type = 'edited_message';
            $message = $payload['edited_message'] ?? null;
        }

        if (!is_array($message)) {
            $message = [];
        }

        $text = $message['text'] ?? $message['caption'] ?? '';
        $entities = isset($message['text']) ? ($message['entities'] ?? []) : ($message['caption_entities'] ?? []);
        if ($update_type === 'callback_query' && isset($payload['callback_query']['data'])) {
            $text = $payload['callback_query']['data'];
            $entities = [];
        }
        $text = $this->normalizeTelegramTextLinks((string)$text, is_array($entities) ? $entities : []);

        $sender = $payload['callback_query']['from'] ?? $message['from'] ?? [];
        $external_user_id = (string)($sender['id'] ?? '');

        $first_name = (string)($sender['first_name'] ?? '');
        $last_name = (string)($sender['last_name'] ?? '');
        $display_name = trim($first_name . ' ' . $last_name);
        $username = (string)($sender['username'] ?? '');
        $profile_url = $username !== '' ? 'https://t.me/' . $username : '';

        $external_message_id = (string)($message['message_id'] ?? '');
        $external_chat_id = (string)($message['chat']['id'] ?? $external_user_id);
        $update_id = (string)($payload['update_id'] ?? '');
        $callback_id = (string)($payload['callback_query']['id'] ?? '');
        $created = (int)($message['date'] ?? 0);
        if ($created <= 0 && isset($payload['callback_query']['message']) && is_array($payload['callback_query']['message'])) {
            $created = (int)($payload['callback_query']['message']['date'] ?? 0);
        }
        if ($update_type === 'callback_query' && $callback_id !== '') {
            $external_message_id = 'callback:' . $callback_id;
        }

        $dedupe_key = '';
        if ($update_id !== '') {
            $dedupe_key = 'telegram:update:' . $update_id;
        } elseif ($callback_id !== '') {
            $dedupe_key = 'telegram:callback:' . $callback_id;
        } elseif ($external_chat_id !== '' && $external_message_id !== '') {
            $dedupe_key = 'telegram:chat:' . $external_chat_id . ':message:' . $external_message_id;
        }

        $attachments = $this->extractAttachments($message);
        $metadata = $this->forwardMetadata($message);
        $chat_type = strtolower((string)($message['chat']['type'] ?? ''));
        $is_start = $update_type === 'message'
            && $chat_type === 'private'
            && preg_match('/^\/start(?:@[A-Za-z0-9_]+)?(?:\s+.*)?$/u', trim((string)$text)) === 1;
        $start_payload = '';
        if ($is_start && preg_match('/^\/start(?:@[A-Za-z0-9_]+)?(?:\s+(.+))?$/u', trim((string)$text), $matches)) {
            $start_payload = trim((string)($matches[1] ?? ''));
        }

        return [
            'update_type' => $update_type,
            'event_kind' => $is_start ? 'conversation_start' : 'message',
            'start_payload' => $start_payload,
            'text' => $text,
            'external_user_id' => $external_user_id,
            'external_chat_id' => $external_chat_id,
            'external_message_id' => $external_message_id,
            'dedupe_key' => $dedupe_key,
            'created' => $created,
            'display_name' => $display_name,
            'username' => $username,
            'profile_url' => $profile_url,
            'attachments' => $attachments,
            'metadata' => $metadata,
        ];
    }

    private function normalizeTelegramTextLinks(string $text, array $entities): string {
        if ($text === '' || !$entities) {
            return $text;
        }

        $replacements = [];
        foreach ($entities as $entity) {
            if (!is_array($entity) || ($entity['type'] ?? '') !== 'text_link') {
                continue;
            }

            $url = (string)($entity['url'] ?? '');
            if (!MessageTextRenderer::isSafeHttpUrl($url)) {
                continue;
            }

            $offset = (int)($entity['offset'] ?? -1);
            $length = (int)($entity['length'] ?? 0);
            if ($offset < 0 || $length <= 0) {
                continue;
            }

            $label = $this->telegramUtf16Slice($text, $offset, $length);
            if ($label === '') {
                continue;
            }

            $replacement = '[' . $this->escapeMarkdownLinkLabel($label) . '](' . trim($url) . ')';
            $replacements[] = [
                'offset' => $offset,
                'length' => $length,
                'replacement' => $replacement,
            ];
        }

        if (!$replacements) {
            return $text;
        }

        usort($replacements, function ($a, $b) {
            return $b['offset'] <=> $a['offset'];
        });

        $utf16 = $this->convertEncoding($text, 'UTF-16LE', 'UTF-8');
        if ($utf16 === '') {
            return $text;
        }
        foreach ($replacements as $replacement) {
            $start = $replacement['offset'] * 2;
            $length = $replacement['length'] * 2;
            if ($start < 0 || $length <= 0 || $start > strlen($utf16)) {
                continue;
            }
            $prefix = substr($utf16, 0, $start);
            $suffix = substr($utf16, $start + $length);
            $middle = $this->convertEncoding($replacement['replacement'], 'UTF-16LE', 'UTF-8');
            $utf16 = $prefix . $middle . $suffix;
        }

        $normalized = $this->convertEncoding($utf16, 'UTF-8', 'UTF-16LE');
        return is_string($normalized) ? $normalized : $text;
    }

    private function telegramUtf16Slice(string $text, int $offset, int $length): string {
        $utf16 = $this->convertEncoding($text, 'UTF-16LE', 'UTF-8');
        if ($utf16 === '') {
            return '';
        }
        $slice = substr($utf16, $offset * 2, $length * 2);
        $decoded = $this->convertEncoding($slice, 'UTF-8', 'UTF-16LE');
        return is_string($decoded) ? $decoded : '';
    }

    private function convertEncoding(string $value, string $to, string $from): string {
        if (function_exists('\\mb_convert_encoding')) {
            $converted = \mb_convert_encoding($value, $to, $from);
            return is_string($converted) ? $converted : '';
        }
        if (function_exists('\\iconv')) {
            $converted = \iconv($from, $to . '//IGNORE', $value);
            return is_string($converted) ? $converted : '';
        }
        return '';
    }

    private function escapeMarkdownLinkLabel(string $label): string {
        return str_replace([']', '['], ['\\]', '\\['], $label);
    }

    public function sendMessage(string $token, string $external_user_id, string $text, array $attachments = [], array $options = []): array {
        $chat_id = $options['external_chat_id'] ?? $external_user_id;
        $text_format = ($options['text_format'] ?? '') === 'html' ? 'html' : 'plain';
        if ((string)$chat_id === '') {
            return ['success' => false, 'error' => 'recipient_missing'];
        }

        if (count($attachments) > 0) {
            $sent = [];
            $caption = trim($text);
            if ($caption !== '' && mb_strlen($caption, 'UTF-8') > 1024) {
                $text_result = $this->sendTextOnly($token, (string)$chat_id, $caption, $text_format);
                if (empty($text_result['success'])) {
                    return $text_result;
                }
                $sent[] = $text_result;
                $caption = '';
            }

            foreach (array_values($attachments) as $index => $attachment) {
                $result = $this->sendWithAttachment($token, (string)$chat_id, $index === 0 ? $caption : '', $attachment, $text_format);
                if (empty($result['success'])) {
                    return $result;
                }
                $sent[] = $result;
            }

            return [
                'success' => true,
                'http_code' => (int)($sent[count($sent) - 1]['http_code'] ?? 200),
                'external_message_id' => (string)($sent[0]['external_message_id'] ?? ''),
                'json' => ['parts' => array_map(function ($item) {
                    return $item['json'] ?? null;
                }, $sent)],
            ];
        }

        if (trim($text) === '') {
            return ['success' => false, 'error' => 'message_empty'];
        }

        return $this->sendTextOnly($token, (string)$chat_id, $text, $text_format);
    }

    private function sendTextOnly(string $token, string $chat_id, string $text, string $text_format = 'plain'): array {
        $body = [
            'chat_id' => $chat_id,
            'text' => mb_substr($text, 0, 4000, 'UTF-8'),
        ];
        if ($text_format === 'html') {
            $body['parse_mode'] = 'HTML';
        }

        $result = $this->apiJson('POST', '/sendMessage', $token, $body);
        if (empty($result['success'])) {
            return $result;
        }

        return [
            'success' => true,
            'http_code' => $result['http_code'],
            'external_message_id' => (string)($result['json']['result']['message_id'] ?? ''),
            'json' => $result['json'],
        ];
    }

    private function sendWithAttachment(string $token, string $chat_id, string $text, array $attachment, string $text_format = 'plain'): array {
        $filename = (string)($attachment['file_name'] ?? $attachment['filename'] ?? '');
        $path = (string)($attachment['path'] ?? '');
        $mime = (string)($attachment['mime_type'] ?? $attachment['mime'] ?? '');
        $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
        if ($extension === '' && $mime !== '') {
            $extension = AttachmentPolicy::extensionForMime($mime);
        }

        if (!is_file($path)) {
            return ['success' => false, 'error' => 'attachment_file_missing'];
        }

        $is_image = AttachmentPolicy::isMaxImageExtension($extension);
        if (!$is_image) {
            $validation = AttachmentPolicy::validateDocumentFile(
                $path,
                $filename,
                (int)filesize($path),
                max(1, (int)ceil(max(1, (int)filesize($path)) / 1024 / 1024))
            );
            if (empty($validation['success'])) {
                return ['success' => false, 'error' => 'attachment_type_unsupported'];
            }
            $mime = (string)$validation['mime'];
        }
        $method = $is_image ? '/sendPhoto' : '/sendDocument';
        $file_field = $is_image ? 'photo' : 'document';

        if ($is_image && $extension === 'webp') {
            $fallback = (new ImageVariantService())->createJpegFallback($path, $filename);
            if (!empty($fallback['success'])) {
                $path = $fallback['path'];
                $mime = $fallback['mime'];
                $filename = $fallback['filename'];
            }
        }

        $curl_file = new CURLFile($path, $mime ?: AttachmentPolicy::mimeForExtension($extension), $this->attachmentDisplayName($attachment, $filename));
        $post_fields = [
            'chat_id' => $chat_id,
            $file_field => $curl_file,
        ];
        if (trim($text) !== '') {
            $post_fields['caption'] = mb_substr($text, 0, 1024, 'UTF-8');
            if ($text_format === 'html') {
                $post_fields['parse_mode'] = 'HTML';
            }
        }

        $url = self::API_BASE . $token . $method;
        $response = $this->http->request('POST', $url, [
            'post_fields' => $post_fields,
            'connect_timeout' => 4,
            'timeout' => 20,
            'trust_profile' => self::PROVIDER,
        ]);

        $raw = $response['raw'];
        $http_code = (int)($response['http_code'] ?? 0);

        if (empty($response['transport_ok']) || $http_code < 200 || $http_code >= 300) {
            $error_json = json_decode((string)$raw, true);
            return [
                'success' => false,
                'error' => is_array($error_json) ? (string)($error_json['description'] ?? 'upload_failed') : 'upload_failed',
                'http_code' => $http_code,
                'details' => $this->transportDetails($response),
            ];
        }

        $json = json_decode((string)$raw, true);
        return [
            'success' => true,
            'http_code' => $http_code,
            'external_message_id' => (string)($json['result']['message_id'] ?? ''),
            'json' => $json,
        ];
    }

    private function attachmentDisplayName(array $attachment, string $fallback): string {
        $name = (string)($attachment['display_name'] ?? '');
        if ($name === '' && !empty($attachment['meta_json'])) {
            $meta = json_decode((string)$attachment['meta_json'], true);
            if (is_array($meta)) {
                $name = (string)($meta['display_name'] ?? '');
            }
        }
        $name = basename(trim($name));
        if ($name === '') {
            $name = basename(trim($fallback));
        }
        return $name !== '' ? $name : 'attachment';
    }

    private function apiJson(string $method, string $path, string $token, ?array $body = null, array $transport_options = []): array {
        $url = self::API_BASE . $token . $path;
        $headers = [
            'Accept: application/json',
        ];
        $request = [
            'headers' => $headers,
            'connect_timeout' => 4,
            'timeout' => 12,
            'trust_profile' => self::PROVIDER,
        ];
        foreach (['proxy', 'proxy_profile', 'connect_timeout', 'timeout', 'allow_tls_fallback'] as $key) {
            if (array_key_exists($key, $transport_options)) {
                $request[$key] = $transport_options[$key];
            }
        }
        if ($body !== null) {
            $headers[] = 'Content-Type: application/json';
            $request['headers'] = $headers;
            $request['body'] = json_encode($body, JSON_UNESCAPED_UNICODE);
        }

        $response = $this->http->request($method, $url, $request);
        $raw = $response['raw'];
        $http_code = (int)($response['http_code'] ?? 0);

        if (empty($response['transport_ok']) || $raw === '') {
            return [
                'success' => false,
                'error' => 'api_request_failed',
                'http_code' => $http_code,
                'details' => $this->transportDetails($response),
            ];
        }

        $json = json_decode((string)$raw, true);
        if (!is_array($json)) {
            return ['success' => false, 'error' => 'api_bad_json', 'http_code' => $http_code];
        }

        if ($http_code < 200 || $http_code >= 300 || empty($json['ok'])) {
            $description = (string)($json['description'] ?? 'api_http_error');
            return [
                'success' => false,
                'error' => $description,
                'http_code' => $http_code,
                'json' => $json,
            ];
        }

        return ['success' => true, 'http_code' => $http_code, 'json' => $json];
    }

    private function transportDetails(array $response): string {
        if (!empty($response['tls_fallback_used'])) {
            return 'tls_fallback';
        }
        if (!empty($response['curl_error'])) {
            return 'curl';
        }
        if (($response['raw'] ?? null) === '') {
            return 'empty';
        }
        return '';
    }

    private function extractAttachments(array $message): array {
        $attachments = [];

        if (isset($message['voice']) && is_array($message['voice'])) {
            $voice = $message['voice'];
            $unique = preg_replace('/[^A-Za-z0-9_-]/', '', (string)($voice['file_unique_id'] ?? $voice['file_id'] ?? 'voice'));
            $attachments[] = [
                'type' => 'audio',
                'telegram_file_id' => (string)($voice['file_id'] ?? ''),
                'file_name' => 'telegram-voice-' . substr($unique, 0, 48) . '.ogg',
                'mime_type' => (string)($voice['mime_type'] ?? 'audio/ogg'),
                'duration' => max(0, (int)($voice['duration'] ?? 0)),
                'file_size' => max(0, (int)($voice['file_size'] ?? 0)),
                'payload_hash' => hash('sha256', 'voice:' . (string)($voice['file_unique_id'] ?? $voice['file_id'] ?? '')),
            ];
        }

        if (isset($message['audio']) && is_array($message['audio'])) {
            $audio = $message['audio'];
            $attachments[] = [
                'type' => 'audio',
                'telegram_file_id' => (string)($audio['file_id'] ?? ''),
                'file_name' => (string)($audio['file_name'] ?? 'telegram-audio.mp3'),
                'mime_type' => (string)($audio['mime_type'] ?? 'audio/mpeg'),
                'duration' => max(0, (int)($audio['duration'] ?? 0)),
                'file_size' => max(0, (int)($audio['file_size'] ?? 0)),
                'payload_hash' => hash('sha256', 'audio:' . (string)($audio['file_unique_id'] ?? $audio['file_id'] ?? '')),
            ];
        }

        if (isset($message['photo']) && is_array($message['photo'])) {
             
            $photo = end($message['photo']);
            $attachments[] = [
                'type' => 'image',
                'telegram_file_id' => (string)($photo['file_id'] ?? ''),
                'payload_hash' => substr(hash('sha256', (string)($photo['file_id'] ?? '')), 0, 16),
            ];
        }

        if (isset($message['document']) && is_array($message['document'])) {
            $doc = $message['document'];
            $attachments[] = [
                'type' => 'document',
                'telegram_file_id' => (string)($doc['file_id'] ?? ''),
                'file_name' => (string)($doc['file_name'] ?? ''),
                'mime_type' => (string)($doc['mime_type'] ?? ''),
                'payload_hash' => substr(hash('sha256', (string)($doc['file_id'] ?? '')), 0, 16),
            ];
        }

        return $attachments;
    }

    




    private function forwardMetadata(array $message): array {
        $origin = $message['forward_origin'] ?? null;
        if (!is_array($origin)) {
            return [];
        }

        $type = strtolower(preg_replace('/[^a-z_]/i', '', trim((string)($origin['type'] ?? ''))));
        $source_name = '';
        if ($type === 'user') {
            $source_name = $this->telegramDisplayName(is_array($origin['sender_user'] ?? null) ? $origin['sender_user'] : []);
        } elseif ($type === 'hidden_user') {
            $source_name = $this->plainForwardLabel((string)($origin['sender_user_name'] ?? ''));
        } elseif ($type === 'chat' || $type === 'channel') {
            $chat = is_array($origin['sender_chat'] ?? null)
                ? $origin['sender_chat']
                : (is_array($origin['chat'] ?? null) ? $origin['chat'] : []);
            $source_name = $this->plainForwardLabel((string)($chat['title'] ?? ''));
            if ($source_name === '') {
                $source_name = $this->telegramDisplayName($chat);
            }
        }

        return [
            'forwarded' => 1,
            'forward_source_name' => $source_name,
            'forward_source_type' => in_array($type, ['user', 'hidden_user', 'chat', 'channel'], true) ? $type : '',
        ];
    }

    private function telegramDisplayName(array $identity): string {
        $name = trim((string)($identity['first_name'] ?? '') . ' ' . (string)($identity['last_name'] ?? ''));
        if ($name === '') {
            $username = ltrim(trim((string)($identity['username'] ?? '')), '@');
            if (preg_match('/^[A-Za-z0-9_]{1,64}$/', $username)) {
                $name = '@' . $username;
            }
        }
        return $this->plainForwardLabel($name);
    }

    private function plainForwardLabel(string $value): string {
        $value = html_entity_decode(strip_tags($value), ENT_QUOTES | ENT_HTML5, 'UTF-8');
        $value = trim((string)preg_replace('/\s+/u', ' ', $value));
        if ($value === '') {
            return '';
        }
        return function_exists('mb_substr') ? mb_substr($value, 0, 120, 'UTF-8') : substr($value, 0, 120);
    }

    public function getFileUrl(string $token, string $file_id, array $options = []): string {
        $result = $this->getFileUrlResult($token, $file_id, $options);
        return !empty($result['success']) ? (string)($result['file_url'] ?? '') : '';
    }

    public function getFileUrlResult(string $token, string $file_id, array $options = []): array {
        $file_id = trim($file_id);
        if ($file_id === '') {
            return ['success' => false, 'error' => 'file_id_missing', 'temporary' => false];
        }

        $result = $this->apiJsonWithDirectRetry('GET', '/getFile?file_id=' . urlencode($file_id), $token, null, $options);
        if (empty($result['success'])) {
            return $this->providerLookupFailure('avatar_file_lookup_failed', $result);
        }

        $file_path = (string)($result['json']['result']['file_path'] ?? '');
        if ($file_path === '') {
            return ['success' => true, 'file_url' => '', 'missing' => true, 'direct_retry' => !empty($result['direct_retry'])];
        }

        return [
            'success' => true,
            'file_url' => 'https://api.telegram.org/file/bot' . $token . '/' . $file_path,
            'missing' => false,
            'direct_retry' => !empty($result['direct_retry']),
        ];
    }

    public function getUserProfileAvatarUrl(string $token, string $user_id, array $options = []): string {
        $result = $this->getUserProfileAvatarLookup($token, $user_id, $options);
        return !empty($result['success']) ? (string)($result['avatar_url'] ?? '') : '';
    }

    public function getUserProfileAvatarLookup(string $token, string $user_id, array $options = []): array {
        $user_id = preg_replace('/\D+/', '', $user_id);
        if ($user_id === '') {
            return ['success' => false, 'error' => 'user_id_missing', 'temporary' => false];
        }

        $result = $this->apiJsonWithDirectRetry('GET', '/getUserProfilePhotos?user_id=' . urlencode($user_id) . '&limit=1', $token, null, $options);
        if (empty($result['success'])) {
            return $this->providerLookupFailure('avatar_profile_lookup_failed', $result);
        }

        $photos = $result['json']['result']['photos'][0] ?? [];
        if (!is_array($photos) || empty($photos)) {
            return ['success' => true, 'avatar_url' => '', 'missing' => true, 'direct_retry' => !empty($result['direct_retry'])];
        }

        $best = [];
        $best_area = 0;
        foreach ($photos as $photo) {
            if (!is_array($photo)) {
                continue;
            }
            $area = max(1, (int)($photo['width'] ?? 0)) * max(1, (int)($photo['height'] ?? 0));
            if ($area >= $best_area) {
                $best_area = $area;
                $best = $photo;
            }
        }

        $file_id = (string)($best['file_id'] ?? '');
        if ($file_id === '') {
            return ['success' => true, 'avatar_url' => '', 'missing' => true, 'direct_retry' => !empty($result['direct_retry'])];
        }

        $file = $this->getFileUrlResult($token, $file_id, !empty($result['direct_retry']) ? $this->directTelegramTransportOptions() : $options);
        if (empty($file['success'])) {
            return $this->providerLookupFailure('avatar_file_lookup_failed', $file);
        }

        return [
            'success' => true,
            'avatar_url' => (string)($file['file_url'] ?? ''),
            'missing' => empty($file['file_url']),
            'direct_retry' => !empty($result['direct_retry']) || !empty($file['direct_retry']),
        ];
    }

    private function apiJsonWithDirectRetry(string $method, string $path, string $token, ?array $body = null, array $transport_options = []): array {
        $result = $this->apiJson($method, $path, $token, $body, $transport_options);
        $result['direct_retry'] = false;

        if (!empty($result['success']) || !$this->shouldRetryTelegramDirect($result, $transport_options)) {
            return $result;
        }

        $direct = $this->apiJson($method, $path, $token, $body, array_merge($transport_options, $this->directTelegramTransportOptions()));
        if (!empty($direct['success'])) {
            $direct['direct_retry'] = true;
            return $direct;
        }

        $result['direct_retry_failed'] = true;
        $result['direct_http_code'] = (int)($direct['http_code'] ?? 0);
        $result['direct_details'] = (string)($direct['details'] ?? '');
        return $result;
    }

    private function shouldRetryTelegramDirect(array $result, array $transport_options): bool {
        if (!empty($result['success'])) {
            return false;
        }
        if (array_key_exists('proxy', $transport_options) && $transport_options['proxy'] === false) {
            return false;
        }
        if (!$this->telegramProxyRouteUsesProxy()) {
            return false;
        }

        $http_code = (int)($result['http_code'] ?? 0);
        $error = strtolower((string)($result['error'] ?? ''));
        $details = strtolower((string)($result['details'] ?? ''));

         
         
        return $http_code === 0
            || $details === 'curl'
            || $details === 'empty'
            || $error === 'api_request_failed';
    }

    private function directTelegramTransportOptions(): array {
        return ['proxy' => false];
    }

    private function telegramProxyRouteUsesProxy(): bool {
        if (!$this->registry) {
            return false;
        }

        try {
            $state = (new ProxyPolicy($this->registry))->routeState('messenger_telegram');
            return (string)($state['code'] ?? '') === 'proxy';
        } catch (\Throwable $e) {
            return false;
        }
    }

    private function providerLookupFailure(string $error, array $result): array {
        return [
            'success' => false,
            'error' => $error,
            'provider_error' => (string)($result['error'] ?? ''),
            'http_code' => (int)($result['http_code'] ?? 0),
            'details' => (string)($result['details'] ?? ''),
            'temporary' => true,
            'direct_retry' => !empty($result['direct_retry']),
            'direct_retry_failed' => !empty($result['direct_retry_failed']),
        ];
    }
}
