package api

import (
	"errors"
	"net/http"
	"strconv"
	"strings"

	"github.com/ez-api/ez-api/internal/model"
	"github.com/ez-api/ez-api/internal/service"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

type MasterRealtimeView struct {
	Requests    int64  `json:"requests"`
	Tokens      int64  `json:"tokens"`
	QPS         int64  `json:"qps"`
	QPSLimit    int64  `json:"qps_limit"`
	RateLimited bool   `json:"rate_limited"`
	UpdatedAt   *int64 `json:"updated_at,omitempty"`
}

func toMasterRealtimeView(stats service.MasterRealtimeSnapshot) *MasterRealtimeView {
	var updatedAt *int64
	if stats.UpdatedAt != nil {
		sec := stats.UpdatedAt.Unix()
		updatedAt = &sec
	}
	return &MasterRealtimeView{
		Requests:    stats.Requests,
		Tokens:      stats.Tokens,
		QPS:         stats.QPS,
		QPSLimit:    stats.QPSLimit,
		RateLimited: stats.RateLimited,
		UpdatedAt:   updatedAt,
	}
}

// GetMasterRealtime godoc
// @Summary      Master realtime stats (admin)
// @Description  Return realtime counters for the specified master
// @Tags         admin
// @Produce      json
// @Security     AdminAuth
// @Param        id   path      int  true  "Master ID"
// @Success      200  {object}  MasterRealtimeView
// @Failure      400  {object}  gin.H
// @Failure      404  {object}  gin.H
// @Failure      500  {object}  gin.H
// @Router       /admin/masters/{id}/realtime [get]
func (h *AdminHandler) GetMasterRealtime(c *gin.Context) {
	idRaw := strings.TrimSpace(c.Param("id"))
	idU64, err := strconv.ParseUint(idRaw, 10, 64)
	if err != nil || idU64 == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid master id"})
		return
	}
	if h.statsService == nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "stats service not configured"})
		return
	}
	var m model.Master
	if err := h.db.Select("id", "global_qps").First(&m, uint(idU64)).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.JSON(http.StatusNotFound, gin.H{"error": "master not found"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load master", "details": err.Error()})
		return
	}

	stats, err := h.statsService.GetMasterRealtimeSnapshot(c.Request.Context(), uint(idU64))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load realtime stats", "details": err.Error()})
		return
	}
	if stats.QPSLimit == 0 && m.GlobalQPS > 0 {
		stats.QPSLimit = int64(m.GlobalQPS)
	}
	c.JSON(http.StatusOK, toMasterRealtimeView(stats))
}

// GetSelfRealtime godoc
// @Summary      Master realtime stats
// @Description  Return realtime counters for the authenticated master
// @Tags         master
// @Produce      json
// @Security     MasterAuth
// @Success      200  {object}  MasterRealtimeView
// @Failure      401  {object}  gin.H
// @Failure      500  {object}  gin.H
// @Router       /v1/realtime [get]
func (h *MasterHandler) GetSelfRealtime(c *gin.Context) {
	master, exists := c.Get("master")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "master key not found in context"})
		return
	}
	if h.statsService == nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "stats service not configured"})
		return
	}
	m := master.(*model.Master)
	stats, err := h.statsService.GetMasterRealtimeSnapshot(c.Request.Context(), m.ID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load realtime stats", "details": err.Error()})
		return
	}
	if stats.QPSLimit == 0 && m.GlobalQPS > 0 {
		stats.QPSLimit = int64(m.GlobalQPS)
	}
	c.JSON(http.StatusOK, toMasterRealtimeView(stats))
}

// SystemRealtimeView represents system-level realtime statistics
type SystemRealtimeView struct {
	QPS              int64                       `json:"qps"`
	RPM              int64                       `json:"rpm"`
	RateLimitedCount int64                       `json:"rate_limited_count"`
	ByMaster         []MasterRealtimeSummaryView `json:"by_master"`
	UpdatedAt        *int64                      `json:"updated_at,omitempty"`
}

// MasterRealtimeSummaryView is a brief summary of a master's realtime stats
type MasterRealtimeSummaryView struct {
	MasterID    uint  `json:"master_id"`
	QPS         int64 `json:"qps"`
	RateLimited bool  `json:"rate_limited"`
}

// GetAdminRealtime godoc
// @Summary      System-level realtime stats (admin)
// @Description  Return aggregated realtime counters across all masters
// @Tags         admin
// @Produce      json
// @Security     AdminAuth
// @Success      200  {object}  SystemRealtimeView
// @Failure      500  {object}  gin.H
// @Router       /admin/realtime [get]
func (h *AdminHandler) GetAdminRealtime(c *gin.Context) {
	if h.statsService == nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "stats service not configured"})
		return
	}

	// Get all active master IDs
	var masterIDs []uint
	if err := h.db.Model(&model.Master{}).
		Where("status = ?", "active").
		Pluck("id", &masterIDs).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load masters", "details": err.Error()})
		return
	}

	stats, err := h.statsService.GetSystemRealtimeSnapshot(c.Request.Context(), masterIDs)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load realtime stats", "details": err.Error()})
		return
	}

	var updatedAt *int64
	if stats.UpdatedAt != nil {
		sec := stats.UpdatedAt.Unix()
		updatedAt = &sec
	}

	byMaster := make([]MasterRealtimeSummaryView, 0, len(stats.ByMaster))
	for _, m := range stats.ByMaster {
		byMaster = append(byMaster, MasterRealtimeSummaryView{
			MasterID:    m.MasterID,
			QPS:         m.QPS,
			RateLimited: m.RateLimited,
		})
	}

	c.JSON(http.StatusOK, SystemRealtimeView{
		QPS:              stats.TotalQPS,
		RPM:              stats.TotalRPM,
		RateLimitedCount: stats.RateLimitedCount,
		ByMaster:         byMaster,
		UpdatedAt:        updatedAt,
	})
}
