package api

import (
	"net/http"
	"time"

	"gitea.hostxtra.co.uk/mrhid6/vantage/server/internal/auth"
	"gitea.hostxtra.co.uk/mrhid6/vantage/server/internal/models"
	"gitea.hostxtra.co.uk/mrhid6/vantage/server/internal/services"
	"github.com/gin-gonic/gin"
	"go.mongodb.org/mongo-driver/v2/bson"
)

func registerMonitorRoutes(g *gin.RouterGroup) {
	g.GET("/monitors", listMonitors)
	g.POST("/monitors", createMonitor)
	g.GET("/monitors/:id", getMonitor)
	g.PUT("/monitors/:id", updateMonitor)
	g.DELETE("/monitors/:id", deleteMonitor)
	g.GET("/monitors/:id/incidents", getMonitorIncidents)
	g.GET("/monitors/:id/uptime", getMonitorUptime)
}

func listMonitors(c *gin.Context) {
	monitors, err := services.ListMonitors(auth.InstanceID(c))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, monitors)
}

func createMonitor(c *gin.Context) {
	var m models.Monitor
	if err := c.ShouldBindJSON(&m); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if m.Name == "" || m.Type == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "name and type are required"})
		return
	}
	if err := services.CheckMonitorLimit(auth.InstanceID(c)); err != nil {
		if limitStatus(c, err) {
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	created, err := services.CreateMonitor(auth.InstanceID(c), &m)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusCreated, created)
}

func getMonitor(c *gin.Context) {
	m, err := services.GetMonitor(auth.InstanceID(c), c.Param("id"))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if m == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "monitor not found"})
		return
	}
	c.JSON(http.StatusOK, m)
}

func updateMonitor(c *gin.Context) {
	var body struct {
		Name        *string               `json:"name"`
		Type        *string               `json:"type"`
		Target      *models.MonitorTarget `json:"target"`
		IntervalSec *int                  `json:"interval_sec"`
		Runner      *string               `json:"runner"`
		Retries     *int                  `json:"retries"`
		Enabled     *bool                 `json:"enabled"`
		ChannelIDs  *[]string             `json:"channel_ids"`
	}
	if err := c.ShouldBindJSON(&body); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	upd := bson.M{}
	if body.Name != nil {
		upd["name"] = *body.Name
	}
	if body.Type != nil {
		upd["type"] = *body.Type
	}
	if body.Target != nil {
		upd["target"] = *body.Target
	}
	if body.IntervalSec != nil {
		upd["interval_sec"] = *body.IntervalSec
	}
	if body.Runner != nil {
		upd["runner"] = *body.Runner
	}
	if body.Retries != nil {
		upd["retries"] = *body.Retries
	}
	if body.Enabled != nil {
		upd["enabled"] = *body.Enabled
	}
	if body.ChannelIDs != nil {
		upd["channel_ids"] = *body.ChannelIDs
	}
	if len(upd) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "no fields to update"})
		return
	}
	if err := services.UpdateMonitor(auth.InstanceID(c), c.Param("id"), upd); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.Status(http.StatusNoContent)
}

func deleteMonitor(c *gin.Context) {
	if err := services.DeleteMonitor(auth.InstanceID(c), c.Param("id")); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.Status(http.StatusNoContent)
}

func getMonitorIncidents(c *gin.Context) {
	m, err := services.GetMonitor(auth.InstanceID(c), c.Param("id"))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if m == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "monitor not found"})
		return
	}
	incidents, err := services.ListIncidents(auth.InstanceID(c), c.Param("id"), 50)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, incidents)
}

func getMonitorUptime(c *gin.Context) {
	m, err := services.GetMonitor(auth.InstanceID(c), c.Param("id"))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if m == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "monitor not found"})
		return
	}
	since := time.Now().Add(-30 * 24 * time.Hour)
	rollups, err := services.UptimeRollups(auth.InstanceID(c), c.Param("id"), since)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, rollups)
}
