<?php

namespace Telegram;

class TelegramSender
{
    private string $token;
    private string $baseUrl = 'https://api.telegram.org/bot';

    public function __construct()
    {
        $this->token = $_ENV['TELEGRAM_BOT_TOKEN'] ?? getenv('TELEGRAM_BOT_TOKEN');
    }

    public function sendMessage(int $chatId, string $text, ?array $keyboard = null, ?string $parseMode = 'HTML'): array
    {
        $data = [
            'chat_id' => $chatId,
            'text' => $text,
            'parse_mode' => $parseMode
        ];

        if ($keyboard) {
            $data['reply_markup'] = json_encode($keyboard);
        }

        return $this->request('sendMessage', $data);
    }

    public function editMessageText(int $chatId, int $messageId, string $text, ?array $keyboard = null, ?string $parseMode = 'HTML'): array
    {
        $data = [
            'chat_id' => $chatId,
            'message_id' => $messageId,
            'text' => $text,
        ];

        if ($parseMode) {
            $data['parse_mode'] = $parseMode;
        }

        if ($keyboard) {
            $data['reply_markup'] = json_encode($keyboard);
        }

        return $this->request('editMessageText', $data);
    }

    public function sendPhoto(int $chatId, string $photo, ?string $caption = null, ?array $keyboard = null): array
    {
        $data = [
            'chat_id' => $chatId,
            'photo' => $photo
        ];

        if ($caption) {
            $data['caption'] = $caption;
            $data['parse_mode'] = 'HTML';
        }

        if ($keyboard) {
            $data['reply_markup'] = json_encode($keyboard);
        }

        return $this->request('sendPhoto', $data);
    }

    public function sendMediaGroup(int $chatId, array $photos, ?string $caption = null): array
    {
        $media = [];
        foreach ($photos as $index => $photo) {
            $media[] = [
                'type' => 'photo',
                'media' => $photo,
                'caption' => $index === 0 ? $caption : null,
                'parse_mode' => 'HTML'
            ];
        }

        $data = [
            'chat_id' => $chatId,
            'media' => json_encode($media)
        ];

        return $this->request('sendMediaGroup', $data);
    }

    public function deleteMessage(int $chatId, int $messageId): array
    {
        return $this->request('deleteMessage', [
            'chat_id' => $chatId,
            'message_id' => $messageId
        ]);
    }

    public function answerCallbackQuery(string $callbackQueryId, string $text, ?bool $showAlert = false)
    {
        return $this->request('answerCallbackQuery', [
            'callback_query_id' => $callbackQueryId,
            'text' => $text,
            'show_alert' => $showAlert
        ]);
    }

    public function getChat(int $chatId): array
    {
        return $this->request('getChat', ['chat_id' => $chatId]);
    }

    public function getChatAdministrators(int $chatId): array
    {
        return $this->request('getChatAdministrators', ['chat_id' => $chatId]);
    }

    public function leaveChat(int $chatId): array
    {
        return $this->request('leaveChat', ['chat_id' => $chatId]);
    }

    public function setChatMenuButton(?int $chatId = null, ?array $menuButton = null): array
    {
        $data = [];
        
        if ($chatId !== null) {
            $data['chat_id'] = $chatId;
        }
        
        if ($menuButton !== null) {
            $data['menu_button'] = json_encode($menuButton);
        }

        return $this->request('setChatMenuButton', $data);
    }

    public function createInlineKeyboard(array $buttons): array
    {
        $keyboard = ['inline_keyboard' => []];
        
        foreach ($buttons as $button) {
            $buttonData = ['text' => $button['text']];
            
            if (isset($button['callback_data'])) {
                $buttonData['callback_data'] = $button['callback_data'];
            } elseif (isset($button['url'])) {
                $buttonData['url'] = $button['url'];
            }
            
            $keyboard['inline_keyboard'][] = [$buttonData];
        }
        
        return $keyboard;
    }

    public function createReplyKeyboard(array $buttons, ?bool $resize = true, ?bool $oneTime = false): array
    {
        $keyboard = [
            'keyboard' => [],
            'resize_keyboard' => $resize,
            'one_time_keyboard' => $oneTime
        ];
        
        foreach ($buttons as $row) {
            $rowButtons = [];
            foreach ($row as $button) {
                $rowButtons[] = [
                    'text' => $button['text'],
                    'request_contact' => $button['request_contact'] ?? false,
                    'request_location' => $button['request_location'] ?? false
                ];
            }
            $keyboard['keyboard'][] = $rowButtons;
        }
        
        return $keyboard;
    }

    public function removeKeyboard(): array
    {
        return ['remove_keyboard' => true];
    }

    private function request(string $method, array $data)
    {
        $url = $this->baseUrl . $this->token . '/' . $method;
        
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        // answerCallbackQuery returns true (boolean) on success
        if ($response === 'true') {
            return true;
        }

        $result = json_decode($response, true);

        if (!$result || !($result['ok'] ?? false)) {
            throw new \Exception("Telegram API Error: " . ($result['description'] ?? 'Unknown error'));
        }

        return $result['result'];
    }

    /**
     * Parsear HTML y dividirlo en segmentos manteniendo el orden
     * Retorna array de ['type' => 'text|image', 'content' => '...', 'src' => '...']
     */
    public function parseContent(string $html): array
    {
        $segments = [];
        
        // Usar regex para encontrar todas las etiquetas <img>
        $pattern = '/<img[^>]+src=["\']([^"\']+)["\'][^>]*>/i';
        $parts = preg_split($pattern, $html, -1, PREG_SPLIT_DELIM_CAPTURE);
        
        // El array parts alterna entre: [texto, src_imagen, texto, src_imagen, texto...]
        for ($i = 0; $i < count($parts); $i++) {
            if ($i % 2 === 0) {
                // Es texto
                $text = $this->htmlToPlainText($parts[$i]);
                if (!empty(trim($text))) {
                    $segments[] = [
                        'type' => 'text',
                        'content' => $text
                    ];
                }
            } else {
                // Es una imagen (el src capturado)
                $segments[] = [
                    'type' => 'image',
                    'src' => $parts[$i],
                    'content' => ''
                ];
            }
        }
        
        return $segments;
    }

    /**
     * Enviar contenido con texto e imágenes en el orden correcto
     */
    public function sendContentWithOrderedImages(int $chatId, array $segments): void
    {
        foreach ($segments as $segment) {
            if ($segment['type'] === 'text') {
                // Enviar texto
                if (!empty(trim($segment['content']))) {
                    $this->sendMessage($chatId, $segment['content']);
                }
            } elseif ($segment['type'] === 'image') {
                $imagePath = $segment['src'];
                
                if (file_exists($imagePath)) {
                    // Es un archivo local
                    $this->sendPhoto($chatId, $imagePath);
                } elseif (strpos($imagePath, 'http') === 0) {
                    // Es una URL remota
                    $this->sendPhoto($chatId, $imagePath);
                }
            }
        }
    }

    /**
     * Convertir HTML a texto plano manteniendo saltos de línea
     */
    private function htmlToPlainText(string $html): string
    {
        // Reemplazar <br>, <p>, etc. con saltos de línea
        $text = preg_replace('/<br\s*\/?>/i', "\n", $html);
        $text = preg_replace('/<\/p>/i', "\n", $text);
        $text = preg_replace('/<p[^>]*>/i', '', $text);
        $text = preg_replace('/<div[^>]*>/i', '', $text);
        $text = preg_replace('/<\/div>/i', "\n", $text);
        
        // Eliminar otras etiquetas HTML
        $text = strip_tags($text);
        
        // Decodificar entidades HTML
        $text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
        
        // Limpiar espacios múltiples y saltos de línea
        $text = preg_replace('/\n{3,}/', "\n\n", $text);
        $text = preg_replace('/[ \t]+/', ' ', $text);
        
        return trim($text);
    }

    public function extractImages(string $html): array
    {
        preg_match_all('/<img[^>]+src=["\']([^"\']+)["\'][^>]*>/i', $html, $matches);
        return $matches[1] ?? [];
    }

    public function removeImages(string $html): string
    {
        return preg_replace('/<img[^>]+>/i', '', $html);
    }

    public function splitMessage(string $content, int $maxLength = 4096): array
    {
        if (strlen($content) <= $maxLength) {
            return [$content];
        }

        $parts = [];
        $lines = explode("\n", $content);
        $currentPart = '';

        foreach ($lines as $line) {
            if (strlen($currentPart . "\n" . $line) > $maxLength) {
                if (!empty($currentPart)) {
                    $parts[] = $currentPart;
                    $currentPart = '';
                }
                
                if (strlen($line) > $maxLength) {
                    $chunks = str_split($line, $maxLength);
                    $parts = array_merge($parts, array_slice($chunks, 0, -1));
                    $currentPart = end($chunks);
                } else {
                    $currentPart = $line;
                }
            } else {
                $currentPart .= (empty($currentPart) ? '' : "\n") . $line;
            }
        }

        if (!empty($currentPart)) {
            $parts[] = $currentPart;
        }

        return $parts;
    }
}
