package controllers

import (
	"io"
	"math"
	"net/http"
	"strconv"
	"strings"
	"time"

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

// SaasIndex renderiza la vista del panel de gestión de productos SaaS.
func SaasIndex(c *fiber.Ctx) error {
	data := fiber.Map{
		"user":    c.Locals("user").(map[string]interface{}),
		"modules": c.Locals("userModules"),
	}
	if err := c.Render("saas", data, "layouts/main"); err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
	}
	return nil
}

// GetSaasProductos devuelve la lista paginada en JSON (para Alpine/HTMX).
func GetSaasProductos(c *fiber.Ctx) error {
	page, _ := strconv.Atoi(c.Query("page", "1"))
	if page < 1 {
		page = 1
	}
	search := c.Query("search", "")
	limit := 10
	offset := (page - 1) * limit

	items, total, err := models.GetAllSaasProductos(limit, offset, search)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
	}

	servicios, _ := models.GetAllServiciosSelect()

	return c.JSON(fiber.Map{
		"items":      items,
		"servicios":  servicios,
		"total":      total,
		"totalPages": int(math.Ceil(float64(total) / float64(limit))),
		"page":       page,
		"limit":      limit,
	})
}

// CreateSaasProducto crea un nuevo producto SaaS.
func CreateSaasProducto(c *fiber.Ctx) error {
	type Req struct {
		Nombre      string `json:"nombre"`
		Slug        string `json:"slug"`
		Descripcion string `json:"descripcion"`
		LogoURL     string `json:"logo_url"`
		ServicioID  *uint  `json:"servicio_id"`
		Activo      bool   `json:"activo"`
		Orden       int    `json:"orden"`
		HealthURL   string `json:"health_url"`
	}
	var req Req
	if err := c.BodyParser(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Datos inválidos"})
	}
	if req.Nombre == "" || req.Slug == "" {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Nombre y slug son obligatorios"})
	}
	item := &models.SaasProducto{
		Nombre:      req.Nombre,
		Slug:        req.Slug,
		Descripcion: req.Descripcion,
		LogoURL:     req.LogoURL,
		ServicioID:  req.ServicioID,
		Activo:      req.Activo,
		Orden:       req.Orden,
		HealthURL:   strings.TrimSpace(req.HealthURL),
	}
	if err := models.CreateSaasProducto(item); err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"message": "Producto SaaS creado", "item": item})
}

// UpdateSaasProducto actualiza un producto SaaS existente.
func UpdateSaasProducto(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "ID inválido"})
	}
	type Req struct {
		Nombre      string `json:"nombre"`
		Slug        string `json:"slug"`
		Descripcion string `json:"descripcion"`
		LogoURL     string `json:"logo_url"`
		ServicioID  *uint  `json:"servicio_id"`
		Activo      bool   `json:"activo"`
		Orden       int    `json:"orden"`
		HealthURL   string `json:"health_url"`
	}
	var req Req
	if err := c.BodyParser(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Datos inválidos"})
	}
	item := &models.SaasProducto{
		Nombre:      req.Nombre,
		Slug:        req.Slug,
		Descripcion: req.Descripcion,
		LogoURL:     req.LogoURL,
		ServicioID:  req.ServicioID,
		Activo:      req.Activo,
		Orden:       req.Orden,
		HealthURL:   strings.TrimSpace(req.HealthURL),
	}
	item.ID = uint(id)
	if err := models.UpdateSaasProducto(item); err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"message": "Producto SaaS actualizado"})
}

// DeleteSaasProducto elimina un producto SaaS.
func DeleteSaasProducto(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "ID inválido"})
	}
	if err := models.DeleteSaasProducto(uint(id)); err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
	}
	return c.JSON(fiber.Map{"message": "Producto SaaS eliminado"})
}

// HealthCheckSaas hace un GET a la HealthURL del producto y devuelve status + latencia.
func HealthCheckSaas(c *fiber.Ctx) error {
	id, err := strconv.ParseUint(c.Params("id"), 10, 32)
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "ID inválido"})
	}
	item, err := models.GetSaasProductoByID(uint(id))
	if err != nil {
		return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "no encontrado"})
	}
	if strings.TrimSpace(item.HealthURL) == "" {
		return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{"error": "Sin URL de health check configurada"})
	}
	client := &http.Client{Timeout: 10 * time.Second}
	start := time.Now()
	resp, reqErr := client.Get(item.HealthURL) //nolint:noctx
	latency := time.Since(start).Milliseconds()
	if reqErr != nil {
		return c.JSON(fiber.Map{"ok": false, "error": reqErr.Error(), "latency_ms": latency})
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(io.LimitReader(resp.Body, 8*1024))
	return c.JSON(fiber.Map{
		"ok":          resp.StatusCode >= 200 && resp.StatusCode < 300,
		"http_status": resp.StatusCode,
		"body":        string(body),
		"latency_ms":  latency,
	})
}
