package controllers

import (
	"log"
	"strings"

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

// ─── Telegram ────────────────────────────────────────────────────────────────

type umindTgChat struct {
	ID int64 `json:"id"`
}

type umindTgFileRef struct {
	FileID string `json:"file_id"`
}

type umindTgMessage struct {
	Chat  umindTgChat      `json:"chat"`
	Text  string           `json:"text"`
	Voice *umindTgFileRef  `json:"voice"`
	Audio *umindTgFileRef  `json:"audio"`
	Photo []umindTgFileRef `json:"photo"`
}

type umindTgUpdate struct {
	Message *umindTgMessage `json:"message"`
}

// UmindTelegramWebhook recibe updates del bot de Telegram de un agente.
// Ruta: POST /webhooks/umind-telegram/:webhook_secret
// El webhook_secret es un identificador nuestro (no el bot token real) —
// ver el comentario en models.UmindCanal.
func UmindTelegramWebhook(c *fiber.Ctx) error {
	secret := c.Params("webhook_secret")
	canal, err := models.GetUmindCanalByWebhookSecret("telegram", secret)
	if err != nil {
		return c.SendStatus(fiber.StatusOK) // siempre 200 a Telegram, aunque no matchee
	}

	var update umindTgUpdate
	if err := c.BodyParser(&update); err != nil || update.Message == nil {
		return c.SendStatus(fiber.StatusOK)
	}
	msg := update.Message

	switch {
	case msg.Voice != nil && msg.Voice.FileID != "":
		err = services.ProcesarMediaTelegramUmind(canal, msg.Chat.ID, msg.Voice.FileID, "audio")
	case msg.Audio != nil && msg.Audio.FileID != "":
		err = services.ProcesarMediaTelegramUmind(canal, msg.Chat.ID, msg.Audio.FileID, "audio")
	case len(msg.Photo) > 0:
		err = services.ProcesarMediaTelegramUmind(canal, msg.Chat.ID, msg.Photo[len(msg.Photo)-1].FileID, "image")
	default:
		texto := strings.TrimSpace(msg.Text)
		if texto == "" {
			return c.SendStatus(fiber.StatusOK)
		}
		err = services.ProcesarMensajeTelegramUmind(canal, msg.Chat.ID, texto)
	}
	if err != nil {
		log.Printf("[UMIND_TELEGRAM] canal %d: %v", canal.ID, err)
		models.RegistrarEventoUmind(canal.AgenteID, "error", "canal_telegram", "Error procesando un mensaje de Telegram", err.Error())
	}
	return c.SendStatus(fiber.StatusOK)
}

// ─── WhatsApp ────────────────────────────────────────────────────────────────

type umindWaMediaRef struct {
	ID string `json:"id"`
}

type umindWaMessage struct {
	From string `json:"from"`
	Type string `json:"type"`
	Text struct {
		Body string `json:"body"`
	} `json:"text"`
	Image umindWaMediaRef `json:"image"`
	Audio umindWaMediaRef `json:"audio"`
}

type umindWaValue struct {
	Metadata struct {
		PhoneNumberID string `json:"phone_number_id"`
	} `json:"metadata"`
	Messages []umindWaMessage `json:"messages"`
}

type umindWaChange struct {
	Value umindWaValue `json:"value"`
}

type umindWaEntry struct {
	Changes []umindWaChange `json:"changes"`
}

type umindWaPayload struct {
	Entry []umindWaEntry `json:"entry"`
}

// UmindWhatsAppVerify atiende el handshake de verificación que Meta hace al
// configurar el webhook (hub.mode/hub.verify_token/hub.challenge).
// Ruta: GET /webhooks/umind-whatsapp/:webhook_secret
func UmindWhatsAppVerify(c *fiber.Ctx) error {
	secret := c.Params("webhook_secret")
	canal, err := models.GetUmindCanalByWebhookSecret("whatsapp", secret)
	if err != nil {
		return c.SendStatus(fiber.StatusForbidden)
	}
	credenciales, err := services.DescifrarCredencialesCanal(canal.CredencialesEnc)
	if err != nil {
		return c.SendStatus(fiber.StatusForbidden)
	}

	if c.Query("hub.mode") != "subscribe" || c.Query("hub.verify_token") != credenciales["verify_token"] || credenciales["verify_token"] == "" {
		return c.SendStatus(fiber.StatusForbidden)
	}
	return c.SendString(c.Query("hub.challenge"))
}

// UmindWhatsAppWebhook recibe mensajes entrantes de WhatsApp Business Cloud
// API. La única autenticación real acá es la firma HMAC del body — el
// webhook_secret en la URL identifica el canal, pero no alcanza solo.
// Ruta: POST /webhooks/umind-whatsapp/:webhook_secret
func UmindWhatsAppWebhook(c *fiber.Ctx) error {
	secret := c.Params("webhook_secret")
	canal, err := models.GetUmindCanalByWebhookSecret("whatsapp", secret)
	if err != nil {
		return c.SendStatus(fiber.StatusOK)
	}
	credenciales, err := services.DescifrarCredencialesCanal(canal.CredencialesEnc)
	if err != nil {
		log.Printf("[UMIND_WHATSAPP] canal %d: credenciales corruptas: %v", canal.ID, err)
		models.RegistrarEventoUmind(canal.AgenteID, "error", "canal_whatsapp", "Credenciales del canal corruptas", err.Error())
		return c.SendStatus(fiber.StatusOK)
	}

	if !services.ValidarFirmaWhatsApp(credenciales["app_secret"], c.Body(), c.Get("X-Hub-Signature-256")) {
		log.Printf("[UMIND_WHATSAPP] canal %d: firma inválida", canal.ID)
		models.RegistrarEventoUmind(canal.AgenteID, "error", "canal_whatsapp", "Firma X-Hub-Signature-256 inválida en un webhook entrante", "")
		return c.SendStatus(fiber.StatusUnauthorized)
	}

	var payload umindWaPayload
	if err := c.BodyParser(&payload); err != nil {
		return c.SendStatus(fiber.StatusOK)
	}
	for _, entry := range payload.Entry {
		for _, change := range entry.Changes {
			for _, msg := range change.Value.Messages {
				var err error
				switch msg.Type {
				case "text":
					texto := strings.TrimSpace(msg.Text.Body)
					if texto == "" {
						continue
					}
					err = services.ProcesarMensajeWhatsAppUmind(canal, msg.From, texto)
				case "audio":
					if msg.Audio.ID == "" {
						continue
					}
					err = services.ProcesarMediaWhatsAppUmind(canal, msg.From, msg.Audio.ID, "audio")
				case "image":
					if msg.Image.ID == "" {
						continue
					}
					err = services.ProcesarMediaWhatsAppUmind(canal, msg.From, msg.Image.ID, "image")
				default:
					continue
				}
				if err != nil {
					log.Printf("[UMIND_WHATSAPP] canal %d: %v", canal.ID, err)
					models.RegistrarEventoUmind(canal.AgenteID, "error", "canal_whatsapp", "Error procesando un mensaje de WhatsApp", err.Error())
				}
			}
		}
	}
	return c.SendStatus(fiber.StatusOK)
}
