package controllers

import (
	"math"
	"strconv"
	"strings"
	"text/template"

	"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"
	"github.com/sujit-baniya/fiber-boilerplate/utils"
)

// ─── Plantillas ─────────────────────────────────────────────────────────────

func PlantillasView(c *fiber.Ctx) error {
	return c.Render("renovaciones/plantillas", fiber.Map{
		"user":    c.Locals("user"),
		"modules": c.Locals("userModules"),
	}, "layouts/main")
}

func GetPlantillas(c *fiber.Ctx) error {
	page, _ := strconv.Atoi(c.Query("page", "1"))
	limit, _ := strconv.Atoi(c.Query("limit", "10"))
	if page < 1 {
		page = 1
	}
	offset := (page - 1) * limit
	records, total, err := models.GetAllPlantillas(limit, offset, c.Query("search"))
	if err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{
		"registros":  records,
		"total":      total,
		"totalPages": int(math.Ceil(float64(total) / float64(limit))),
		"page":       page,
	})
}

func CreatePlantilla(c *fiber.Ctx) error {
	var m models.PlantillaCorreo
	if err := c.BodyParser(&m); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": err.Error()})
	}
	if m.CuerpoHTML != "" {
		if _, err := template.New("validate").Parse(m.CuerpoHTML); err != nil {
			return c.Status(400).JSON(fiber.Map{"error": "Sintaxis inválida en el HTML: " + err.Error()})
		}
	}
	if err := models.CreatePlantilla(m); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.Status(201).JSON(fiber.Map{"message": "Plantilla creada", "ok": true})
}

func UpdatePlantilla(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
	}
	var updates map[string]interface{}
	if err := c.BodyParser(&updates); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": err.Error()})
	}
	if html, ok := updates["cuerpo_html"].(string); ok && html != "" {
		if _, err := template.New("validate").Parse(html); err != nil {
			return c.Status(400).JSON(fiber.Map{"error": "Sintaxis inválida en el HTML: " + err.Error()})
		}
	}
	if err := models.UpdatePlantilla(uint(id), updates); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"message": "Actualizado", "ok": true})
}

func DeletePlantilla(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
	}
	if err := models.DeletePlantilla(uint(id)); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"message": "Eliminado", "ok": true})
}

func PreviewPlantilla(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
	}
	p, err := models.GetPlantillaByID(uint(id))
	if err != nil {
		return c.Status(404).JSON(fiber.Map{"error": "No encontrada"})
	}
	html, err := services.RenderPlantilla(p, services.DatosEjemplo())
	if err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"html": html, "ok": true})
}

// ValidarPlantilla comprueba si el CuerpoHTML es un Go template válido
func ValidarPlantilla(c *fiber.Ctx) error {
	var body struct {
		HTML string `json:"html"`
	}
	if err := c.BodyParser(&body); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": err.Error()})
	}
	html := strings.TrimSpace(body.HTML)
	if html == "" {
		return c.JSON(fiber.Map{"ok": true})
	}
	if _, err := template.New("validate").Parse(html); err != nil {
		return c.Status(400).JSON(fiber.Map{"ok": false, "error": err.Error()})
	}
	return c.JSON(fiber.Map{"ok": true})
}

func TestEnvioPlantilla(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
	}
	var body struct {
		Email string `json:"email"`
	}
	if err := c.BodyParser(&body); err != nil || body.Email == "" {
		return c.Status(400).JSON(fiber.Map{"error": "Email requerido"})
	}
	p, err := models.GetPlantillaByID(uint(id))
	if err != nil {
		return c.Status(404).JSON(fiber.Map{"error": "No encontrada"})
	}

	// Recargar siempre la config activa desde BD antes de enviar
	if cfg, err2 := models.GetSmtpConfig(); err2 == nil {
		app.Http.Mail.Host = cfg.Host
		app.Http.Mail.Port = cfg.Port
		app.Http.Mail.Username = cfg.Username
		app.Http.Mail.Password = utils.Decrypt(cfg.Password, app.Http.Server.Key)
		app.Http.Mail.Encryption = cfg.Encryption
		app.Http.Mail.FromAddress = cfg.FromAddress
		app.Http.Mail.FromName = cfg.FromName
		app.Http.Mail.SetupMailer()
	}

	if err := services.EnviarCorreoPrueba(body.Email, p); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"message": "Correo enviado", "ok": true})
}

// ─── Reglas ──────────────────────────────────────────────────────────────────

func ReglasView(c *fiber.Ctx) error {
	return c.Render("renovaciones/reglas", fiber.Map{
		"user":    c.Locals("user"),
		"modules": c.Locals("userModules"),
	}, "layouts/main")
}

func GetReglas(c *fiber.Ctx) error {
	records, err := models.GetAllReglas()
	if err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"registros": records, "total": len(records)})
}

func CreateRegla(c *fiber.Ctx) error {
	var m models.NotificacionRegla
	if err := c.BodyParser(&m); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": err.Error()})
	}
	if err := models.CreateRegla(m); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.Status(201).JSON(fiber.Map{"message": "Regla creada", "ok": true})
}

func UpdateRegla(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
	}
	var m models.NotificacionRegla
	if err := c.BodyParser(&m); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": err.Error()})
	}
	m.ID = uint(id)
	if err := models.UpdateRegla(m); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"message": "Actualizado", "ok": true})
}

func DeleteRegla(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
	}
	if err := models.DeleteRegla(uint(id)); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"message": "Eliminado", "ok": true})
}

// ─── Historial ───────────────────────────────────────────────────────────────

func HistorialView(c *fiber.Ctx) error {
	return c.Render("renovaciones/historial", fiber.Map{
		"user":    c.Locals("user"),
		"modules": c.Locals("userModules"),
	}, "layouts/main")
}

func GetHistorial(c *fiber.Ctx) error {
	page, _ := strconv.Atoi(c.Query("page", "1"))
	limit, _ := strconv.Atoi(c.Query("limit", "20"))
	if page < 1 {
		page = 1
	}
	offset := (page - 1) * limit
	records, total, err := models.GetAllLogs(limit, offset)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{
		"registros":  records,
		"total":      total,
		"totalPages": int(math.Ceil(float64(total) / float64(limit))),
		"page":       page,
	})
}

func ReenviarNotificacion(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
	}
	log, err := models.GetLogByID(uint(id))
	if err != nil {
		return c.Status(404).JSON(fiber.Map{"error": "No encontrado"})
	}
	if err := services.ReenviarLog(log); err != nil {
		return c.Status(500).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"message": "Reenviado", "ok": true})
}

func VerPreviewLog(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
	}
	log, err := models.GetLogByID(uint(id))
	if err != nil {
		return c.Status(404).JSON(fiber.Map{"error": "No encontrado"})
	}
	return c.JSON(fiber.Map{"html": log.PreviewHTML, "asunto": log.Asunto, "ok": true})
}
