package services

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"

	"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
)

// ProcesarMensajeTelegramUmind adapta un mensaje entrante del canal Telegram
// de un agente al mismo motor que atiende el widget web
// (ProcessWidgetMessage) y responde usando el bot token propio del canal
// (no el bot interno de staff). La sesión se separa por chat_id con un
// prefijo para no colisionar con session_ids del widget.
func ProcesarMensajeTelegramUmind(canal *models.UmindCanal, chatID int64, texto string) error {
	agente, err := models.GetUmindAgenteByID(canal.AgenteID)
	if err != nil || !agente.Activo {
		return fmt.Errorf("agente no encontrado o inactivo: %w", err)
	}

	credenciales, err := DescifrarCredencialesCanal(canal.CredencialesEnc)
	if err != nil {
		return fmt.Errorf("credenciales del canal corruptas: %w", err)
	}
	botToken := credenciales["bot_token"]
	if botToken == "" {
		return fmt.Errorf("el canal no tiene bot_token configurado")
	}

	sessionID := fmt.Sprintf("tg:%d", chatID)
	respuesta, err := ProcessWidgetMessage(agente, sessionID, texto)
	if err != nil {
		return fmt.Errorf("error del agente: %w", err)
	}

	return (&TelegramService{}).SendMessageWithToken(chatID, respuesta, botToken)
}

// ProcesarMediaTelegramUmind atiende notas de voz/audio y fotos entrantes:
// si el canal tiene la conversión habilitada, descarga el archivo vía
// getFile, lo pasa por Whisper/OCR y responde igual que un mensaje de texto.
// Si no está habilitada, se ignora en silencio.
func ProcesarMediaTelegramUmind(canal *models.UmindCanal, chatID int64, fileID, tipo string) error {
	agente, err := models.GetUmindAgenteByID(canal.AgenteID)
	if err != nil || !agente.Activo {
		return fmt.Errorf("agente no encontrado o inactivo: %w", err)
	}
	credenciales, err := DescifrarCredencialesCanal(canal.CredencialesEnc)
	if err != nil {
		return fmt.Errorf("credenciales del canal corruptas: %w", err)
	}
	botToken := credenciales["bot_token"]
	if botToken == "" {
		return fmt.Errorf("el canal no tiene bot_token configurado")
	}

	var texto string
	switch tipo {
	case "audio":
		if !canal.UsarWhisperAudio {
			return nil
		}
		data, err := descargarArchivoTelegram(botToken, fileID)
		if err != nil {
			return fmt.Errorf("no se pudo descargar el audio de Telegram: %w", err)
		}
		texto, err = TranscribirAudioSelfHosted(data, "audio.ogg")
		if err != nil {
			return err
		}
	case "image":
		if !canal.UsarOcrImagenes {
			return nil
		}
		data, err := descargarArchivoTelegram(botToken, fileID)
		if err != nil {
			return fmt.Errorf("no se pudo descargar la imagen de Telegram: %w", err)
		}
		texto, err = ExtraerTextoOCR(data, "image/jpeg")
		if err != nil {
			return err
		}
	default:
		return nil
	}
	if strings.TrimSpace(texto) == "" {
		return fmt.Errorf("no se pudo extraer texto del %s recibido", tipo)
	}

	sessionID := fmt.Sprintf("tg:%d", chatID)
	respuesta, err := ProcessWidgetMessage(agente, sessionID, texto)
	if err != nil {
		return fmt.Errorf("error del agente: %w", err)
	}
	return (&TelegramService{}).SendMessageWithToken(chatID, respuesta, botToken)
}

// descargarArchivoTelegram resuelve el file_path de un file_id (getFile) y
// descarga el archivo desde el CDN de archivos de Telegram.
func descargarArchivoTelegram(botToken, fileID string) ([]byte, error) {
	getFileURL := fmt.Sprintf("https://api.telegram.org/bot%s/getFile?file_id=%s", botToken, url.QueryEscape(fileID))
	resp, err := telegramHTTPClient.Get(getFileURL)
	if err != nil {
		return nil, fmt.Errorf("no se pudo consultar getFile: %w", err)
	}
	defer resp.Body.Close()
	var out struct {
		Result struct {
			FilePath string `json:"file_path"`
		} `json:"result"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&out); err != nil || out.Result.FilePath == "" {
		return nil, fmt.Errorf("respuesta inesperada de getFile")
	}

	fileURL := fmt.Sprintf("https://api.telegram.org/file/bot%s/%s", botToken, out.Result.FilePath)
	resp2, err := telegramHTTPClient.Get(fileURL)
	if err != nil {
		return nil, fmt.Errorf("no se pudo descargar el archivo: %w", err)
	}
	defer resp2.Body.Close()
	return io.ReadAll(io.LimitReader(resp2.Body, 20*1024*1024))
}

// RegistrarWebhookTelegram le dice a Telegram a qué URL mandar los updates
// del bot — se llama una vez al crear el canal (o al reconfigurar el token).
func RegistrarWebhookTelegram(botToken, webhookURL string) error {
	if botToken == "" || webhookURL == "" {
		return fmt.Errorf("bot_token y webhookURL son requeridos")
	}
	api := fmt.Sprintf("https://api.telegram.org/bot%s/setWebhook?url=%s", botToken, url.QueryEscape(webhookURL))
	resp, err := telegramHTTPClient.Get(api)
	if err != nil {
		return fmt.Errorf("no se pudo contactar la API de Telegram: %w", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("Telegram respondió %d al registrar el webhook", resp.StatusCode)
	}
	return nil
}
