<?php

namespace Discord;

class DiscordSender
{
    private string $token;
    private string $guildId;
    private string $baseUrl = 'https://discord.com/api/v10';

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

    public function sendMessage(string $channelId, string $content, ?array $embed = null, ?array $buttons = null): array
    {
        $channelId = $this->resolveUserToDmChannel($channelId);
        
        $data = ['content' => $content];

        if ($embed) {
            $data['embeds'] = [$embed];
        }

        if ($buttons) {
            // Construir componentes correctamente
            $components = [];
            
            foreach ($buttons as $row) {
                if (isset($row['components']) && is_array($row['components'])) {
                    $componentRow = [
                        'type' => 1,
                        'components' => []
                    ];
                    
                    foreach ($row['components'] as $btn) {
                        $componentRow['components'][] = [
                            'type' => 2,
                            'style' => isset($btn['style']) ? intval($btn['style']) : 1,
                            'label' => $btn['label'],
                            'custom_id' => $btn['custom_id']
                        ];
                    }
                    
                    $components[] = $componentRow;
                }
            }
            
            if (!empty($components)) {
                $data['components'] = $components;
            }
        }

        return $this->request("POST", "/channels/{$channelId}/messages", $data);
    }
    
    private function cleanComponents(array $components): array
    {
        $clean = [];
        
        foreach ($components as $row) {
            $cleanRow = [];
            
            if (isset($row['components'])) {
                $cleanComponents = [];
                foreach ($row['components'] as $btn) {
                    $cleanBtn = [
                        'type' => 2,
                        'style' => $btn['style'] ?? 1,
                        'label' => $btn['label'],
                        'custom_id' => $btn['custom_id']
                    ];
                    $cleanComponents[] = $cleanBtn;
                }
                $cleanRow = [
                    'type' => 1,
                    'components' => $cleanComponents
                ];
            } else {
                $cleanRow = $row;
            }
            
            $clean[] = $cleanRow;
        }
        
        return $clean;
    }

    public function sendMessageWithImages(string $channelId, string $content, array $images, ?array $buttons = null): array
    {
        $channelId = $this->resolveUserToDmChannel($channelId);
        
        $result = null;
        
        if (!empty($images)) {
            // Verificar si las imágenes son locales o URLs
            $localImages = [];
            $remoteImages = [];
            
            foreach ($images as $imageUrl) {
                if (strpos($imageUrl, 'http') === 0) {
                    // Es una URL remota
                    $remoteImages[] = $imageUrl;
                } elseif (file_exists($imageUrl)) {
                    // Es un archivo local
                    $localImages[] = $imageUrl;
                }
            }
            
            // Enviar imágenes locales como adjuntos
            if (!empty($localImages)) {
                $result = $this->sendMessageWithAttachments($channelId, $content, $localImages);
            } else {
                $result = $this->sendMessage($channelId, $content, null, $buttons);
            }
            
            // Enviar imágenes remotas como embeds
            foreach ($remoteImages as $imageUrl) {
                $embed = [
                    'image' => ['url' => $imageUrl]
                ];
                $result = $this->sendMessage($channelId, '', $embed, $buttons);
                $buttons = null; // Solo enviar botones en el primer mensaje
            }
        } else {
            $result = $this->sendMessage($channelId, $content, null, $buttons);
        }

        return $result;
    }

    /**
     * Enviar contenido con texto e imágenes en el orden correcto
     * Divide el contenido en segmentos y los envía manteniendo el orden
     */
    public function sendContentWithOrderedImages(string $channelId, array $segments): void
    {
        $channelId = $this->resolveUserToDmChannel($channelId);
        
        foreach ($segments as $segment) {
            if ($segment['type'] === 'text') {
                // Enviar texto
                if (!empty(trim($segment['content']))) {
                    $this->sendMessage($channelId, $segment['content']);
                }
            } elseif ($segment['type'] === 'image') {
                // Enviar imagen
                $imagePath = $segment['src'];
                
                if (strpos($imagePath, 'http') === 0) {
                    // URL remota - enviar como embed
                    $embed = ['image' => ['url' => $imagePath]];
                    $this->sendMessage($channelId, '', $embed);
                } elseif (file_exists($imagePath)) {
                    // Archivo local - enviar como adjunto
                    $this->sendMessageWithAttachments($channelId, '', [$imagePath]);
                }
            }
        }
    }

    public function sendMessageWithAttachments(string $channelId, string $content, array $files): array
    {
        $channelId = $this->resolveUserToDmChannel($channelId);
        
        $url = $this->baseUrl . "/channels/{$channelId}/messages";
        
        // Preparar los datos multipart
        $postData = [
            'content' => $content,
            'payload_json' => json_encode(['content' => $content])
        ];
        
        // Agregar archivos
        $fileIndex = 0;
        foreach ($files as $filePath) {
            if (file_exists($filePath)) {
                $postData["file{$fileIndex}"] = new \CURLFile($filePath, mime_content_type($filePath), basename($filePath));
                $fileIndex++;
            }
        }
        
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Authorization: Bot ' . $this->token,
        ]);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);

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

        $result = json_decode($response, true);

        if ($httpCode >= 400) {
            throw new \Exception("Discord API Error: " . ($result['message'] ?? 'Unknown error'));
        }

        return $result;
    }

    public function editMessage(string $channelId, string $messageId, string $content, ?array $embed = null): array
    {
        $data = ['content' => $content];
        
        if ($embed) {
            $data['embeds'] = [$embed];
        }

        return $this->request("PATCH", "/channels/{$channelId}/messages/{$messageId}", $data);
    }

    public function deleteMessage(string $channelId, string $messageId): bool
    {
        $this->request("DELETE", "/channels/{$channelId}/messages/{$messageId}");
        return true;
    }

    public function getChannel(string $channelId): array
    {
        return $this->request("GET", "/channels/{$channelId}");
    }

    public function getGuildChannels(): array
    {
        return $this->request("GET", "/guilds/{$this->guildId}/channels");
    }

    private function buildActionRow(array $buttons): array
    {
        $components = [];
        
        foreach ($buttons as $button) {
            $component = [
                'type' => 2,
                'style' => $button['style'] ?? 1,
                'label' => $button['label'],
                'custom_id' => $button['custom_id']
            ];
            
            if (isset($button['url'])) {
                $component['url'] = $button['url'];
            }
            
            $components[] = $component;
        }

        return [
            [
                'type' => 1,
                'components' => $components
            ]
        ];
    }

    private function request(string $method, string $endpoint, ?array $data = null): array
    {
        $url = $this->baseUrl . $endpoint;
        
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Authorization: Bot ' . $this->token,
            'Content-Type: application/json'
        ]);

        if ($data) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        }

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

        $result = json_decode($response, true);

        if ($httpCode >= 400) {
            throw new \Exception("Discord API Error: " . ($result['message'] ?? 'Unknown error'));
        }

        return $result;
    }
    
    private function resolveUserToDmChannel(string $userId): string
    {
        try {
            $response = $this->request("POST", "/users/{$userId}/channels", [
                'recipient_id' => $userId
            ]);
            
            if (isset($response['id'])) {
                return $response['id'];
            }
        } catch (\Exception $e) {
            error_log("Error creating DM channel: " . $e->getMessage());
        }
        
        return $userId;
    }

    public function splitMessage(string $content, int $maxLength = 2000): 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;
    }

    /**
     * Parsear HTML y dividirlo en segmentos manteniendo el orden
     * Retorna array de ['type' => 'text|image', 'content' => '...', 'src' => '...']
     */
    public function parseContent(string $html): array
    {
        $segments = [];
        $currentText = '';
        
        // 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;
    }
    
    /**
     * 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);
    }
}
