package controllers

import (
	"log"
	"strconv"
	"strings"

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

// ─── Webhook de correo entrante ───────────────────────────────────────────────
// Recibe notificaciones de SendGrid, Mailgun, etc.
// POST /webhooks/soporte/:provider
// provider: sendgrid, mailgun, generic

func SoporteWebhook(c *fiber.Ctx) error {
	provider := c.Params("provider", "generic")

	cfg, err := models.GetSoporteWebhookActivo()
	if err != nil {
		log.Printf("[SoporteWebhook] Sin config activa: %v", err)
		return c.Status(200).JSON(fiber.Map{"ok": false, "error": "sin config"})
	}

	var emails []struct {
		From     string `json:"from" form:"from"`
		Subject  string `json:"subject" form:"subject"`
		Text     string `json:"text" form:"text"`
		Html     string `json:"html" form:"html"`
		Sender   string `json:"sender" form:"sender"`
		FromName string `json:"from_name" form:"from_name"`
	}

	switch provider {
	case "sendgrid":
		var sg struct {
			From     string `json:"from"`
			Subject  string `json:"subject"`
			Text     string `json:"text"`
			Html     string `json:"html"`
			Sender   string `json:"sender"`
			FromName string `json:"from_name"`
		}
		if err := c.BodyParser(&sg); err != nil {
			return c.Status(200).JSON(fiber.Map{"ok": false, "error": "body inválido"})
		}
		emails = append(emails, struct {
			From     string `json:"from" form:"from"`
			Subject  string `json:"subject" form:"subject"`
			Text     string `json:"text" form:"text"`
			Html     string `json:"html" form:"html"`
			Sender   string `json:"sender" form:"sender"`
			FromName string `json:"from_name" form:"from_name"`
		}{From: sg.From, Subject: sg.Subject, Text: sg.Text, Html: sg.Html, Sender: sg.Sender, FromName: sg.FromName})
	case "mailgun":
		var mg struct {
			From        string `form:"from"`
			Subject     string `form:"subject"`
			Text        string `form:"body-plain"`
			Html        string `form:"body-html"`
			Sender      string `form:"sender"`
			FromName    string `form:"from_name"`
		}
		if err := c.BodyParser(&mg); err != nil {
			return c.Status(200).JSON(fiber.Map{"ok": false})
		}
		emails = append(emails, struct {
			From     string `json:"from" form:"from"`
			Subject  string `json:"subject" form:"subject"`
			Text     string `json:"text" form:"text"`
			Html     string `json:"html" form:"html"`
			Sender   string `json:"sender" form:"sender"`
			FromName string `json:"from_name" form:"from_name"`
		}{
			From: mg.From, Subject: mg.Subject, Text: mg.Text,
			Html: mg.Html, Sender: mg.Sender, FromName: mg.FromName,
		})
	default:
		var generic struct {
			From     string `json:"from"`
			Subject  string `json:"subject"`
			Text     string `json:"text"`
			Html     string `json:"html"`
		}
		if err := c.BodyParser(&generic); err != nil {
			return c.Status(200).JSON(fiber.Map{"ok": false})
		}
		emails = append(emails, struct {
			From     string `json:"from" form:"from"`
			Subject  string `json:"subject" form:"subject"`
			Text     string `json:"text" form:"text"`
			Html     string `json:"html" form:"html"`
			Sender   string `json:"sender" form:"sender"`
			FromName string `json:"from_name" form:"from_name"`
		}{
			From: generic.From, Subject: generic.Subject, Text: generic.Text, Html: generic.Html,
		})
	}

	for _, e := range emails {
		if e.From == "" || e.Subject == "" {
			continue
		}
		fromEmail := extractEmail(e.From)
		fromName := e.FromName
		if fromName == "" {
			fromName = extractName(e.From)
		}
		if fromName == "" {
			fromName = fromEmail
		}

		contenido := e.Text
		if contenido == "" {
			contenido = e.Html
		}
		contenido = strings.TrimSpace(contenido)
		if len(contenido) > 5000 {
			contenido = contenido[:5000]
		}

		ticket := &models.ProyectoTicket{
			AutorNombre: fromName,
			EmailFrom:   fromEmail,
			Titulo:      e.Subject,
			Descripcion: contenido,
			Estado:      "abierto",
			Origen:      "email",
		}
		if cfg.AsignarA != nil {
			ticket.AsignadoA = cfg.AsignarA
		}
		if err := models.CreateProyectoTicket(ticket); err != nil {
			log.Printf("[SoporteWebhook] Error creando ticket: %v", err)
			continue
		}
		log.Printf("[SoporteWebhook] Ticket #%d creado desde email (%s): %s", ticket.ID, fromEmail, e.Subject)

		// Notificar admin
		services.SendSoporteNotifAdmin(ticket)

		// Auto-responder
		if cfg.ResponderAuto {
			services.SendSoporteAutoRespuesta(ticket)
		}
	}

	return c.Status(200).JSON(fiber.Map{"ok": true})
}

// ─── Asignar ticket a usuario ─────────────────────────────────────────────────
// PUT /app/tickets/:ticketID/asignar

func AsignarTicket(c *fiber.Ctx) error {
	ticketID, _ := strconv.ParseUint(c.Params("ticketID"), 10, 32)
	type Req struct{ AsignadoID uint `json:"asignado_id"` }
	var req Req
	if err := c.BodyParser(&req); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "body inválido"})
	}
	if err := app.Http.Database.DB.Model(&models.ProyectoTicket{}).
		Where("id = ?", ticketID).
		Update("asignado_a", req.AsignadoID).Error; err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"ok": true})
}

// ─── Listar admins para asignación ────────────────────────────────────────────
// GET /app/tickets/admins

func GetSoporteAdmins(c *fiber.Ctx) error {
	var admins []models.Users
	app.Http.Database.DB.Where("is_admin = ?", true).
		Or("role_id IN (SELECT id FROM roles WHERE name = 'soporte' OR name = 'admin')").
		Find(&admins)
	type item struct {
		ID   uint   `json:"id"`
		Name string `json:"name"`
	}
	result := make([]item, 0)
	for _, a := range admins {
		result = append(result, item{ID: a.ID, Name: a.Name})
	}
	return c.JSON(result)
}

// ─── Configuración del webhook ────────────────────────────────────────────────

func SoporteWebhookConfigPage(c *fiber.Ctx) error {
	cfg, _ := models.GetSoporteWebhookActivo()
	return c.Render("soporte_webhook", fiber.Map{
		"user":    c.Locals("user"),
		"modules": c.Locals("userModules"),
		"cfg":     cfg,
	}, "layouts/main")
}

func GetSoporteWebhookConfig(c *fiber.Ctx) error {
	cfg, err := models.GetSoporteWebhookActivo()
	if err != nil {
		return c.JSON(fiber.Map{"data": nil})
	}
	return c.JSON(fiber.Map{"data": cfg})
}

func SaveSoporteWebhookConfig(c *fiber.Ctx) error {
	type body struct {
		ID         uint   `json:"id"`
		Nombre     string `json:"nombre"`
		Provider   string `json:"provider"`
		ApiKey     string `json:"api_key"`
		EmailDestino string `json:"email_destino"`
		ResponderAuto bool `json:"responder_auto"`
		MensajeAuto   string `json:"mensaje_auto"`
		AsignarA    *uint  `json:"asignar_a"`
		SmtpHost      string `json:"smtp_host"`
		SmtpPort      int    `json:"smtp_port"`
		SmtpUsername  string `json:"smtp_username"`
		SmtpPassword  string `json:"smtp_password"`
		SmtpEncryption string `json:"smtp_encryption"`
		SmtpFromAddr  string `json:"smtp_from_addr"`
		SmtpFromName  string `json:"smtp_from_name"`
	}
	var b body
	if err := c.BodyParser(&b); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "body inválido"})
	}
	port := b.SmtpPort
	if port == 0 {
		port = 587
	}
	enc := b.SmtpEncryption
	if enc == "" {
		enc = "starttls"
	}
	cfg := &models.SoporteWebhookConfig{
		Nombre:        b.Nombre,
		Provider:      b.Provider,
		ApiKey:        b.ApiKey,
		EmailDestino:  b.EmailDestino,
		ResponderAuto: b.ResponderAuto,
		MensajeAuto:   b.MensajeAuto,
		AsignarA:      b.AsignarA,
		SmtpHost:      b.SmtpHost,
		SmtpPort:      port,
		SmtpUsername:  b.SmtpUsername,
		SmtpPassword:  b.SmtpPassword,
		SmtpEncryption: enc,
		SmtpFromAddr:  b.SmtpFromAddr,
		SmtpFromName:  b.SmtpFromName,
		Activo:        true,
	}
	cfg.ID = b.ID
	if err := models.SaveSoporteWebhookConfig(cfg); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"ok": true})
}

// ─── helpers ──────────────────────────────────────────────────────────────────

func extractEmail(s string) string {
	s = strings.TrimSpace(s)
	if idx := strings.LastIndex(s, "<"); idx >= 0 {
		s = s[idx+1:]
	}
	if idx := strings.LastIndex(s, ">"); idx >= 0 {
		s = s[:idx]
	}
	return strings.TrimSpace(s)
}

func extractName(s string) string {
	s = strings.TrimSpace(s)
	if idx := strings.Index(s, "<"); idx >= 0 {
		return strings.TrimSpace(s[:idx])
	}
	return ""
}
