package admin

import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/rose_cat707/luminary/internal/model"
)

func (h *Handler) ListIPRules(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"data": h.cache.ListIPRules()})
}

func (h *Handler) CreateIPRule(c *gin.Context) {
	var req struct {
		CIDR    string            `json:"cidr"`
		Type    model.IPRuleType  `json:"type"`
		Scope   model.IPRuleScope `json:"scope"`
		Enabled *bool             `json:"enabled"`
	}
	if err := c.ShouldBindJSON(&req); err != nil || req.CIDR == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
		return
	}
	if req.Type == "" {
		req.Type = model.IPRuleAllow
	}
	if req.Scope == "" {
		req.Scope = model.IPScopeProxy
	}
	rule := model.IPRule{CIDR: req.CIDR, Type: req.Type, Scope: req.Scope, Enabled: true}
	if req.Enabled != nil {
		rule.Enabled = *req.Enabled
	}
	if err := h.db.DB().Create(&rule).Error; err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	rules := h.cache.ListIPRules()
	rules = append(rules, rule)
	h.cache.SetIPRules(rules)
	c.JSON(http.StatusCreated, rule)
}

func (h *Handler) UpdateIPRule(c *gin.Context) {
	id := parseUint(c.Param("id"))
	var rule model.IPRule
	if err := h.db.DB().First(&rule, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
		return
	}
	var req struct {
		CIDR    string            `json:"cidr"`
		Type    model.IPRuleType  `json:"type"`
		Scope   model.IPRuleScope `json:"scope"`
		Enabled *bool             `json:"enabled"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
		return
	}
	if req.CIDR != "" {
		rule.CIDR = req.CIDR
	}
	if req.Type != "" {
		rule.Type = req.Type
	}
	if req.Scope != "" {
		rule.Scope = req.Scope
	}
	if req.Enabled != nil {
		rule.Enabled = *req.Enabled
	}
	h.db.DB().Save(&rule)
	h.reloadIPRules()
	c.JSON(http.StatusOK, rule)
}

func (h *Handler) DeleteIPRule(c *gin.Context) {
	id := parseUint(c.Param("id"))
	h.db.DB().Delete(&model.IPRule{}, id)
	h.reloadIPRules()
	c.JSON(http.StatusOK, gin.H{"ok": true})
}

func (h *Handler) reloadIPRules() {
	var rules []model.IPRule
	h.db.DB().Find(&rules)
	h.cache.SetIPRules(rules)
}

func (h *Handler) DashboardOverview(c *gin.Context) {
	since := time.Now().Add(-24 * time.Hour)
	var totalRequests int64
	var totalTokens int64
	var errorCount int64
	h.db.DB().Model(&model.UsageRecord{}).Where("created_at >= ?", since).Count(&totalRequests)
	h.db.DB().Model(&model.UsageRecord{}).Where("created_at >= ?", since).Select("COALESCE(SUM(tokens_in + tokens_out), 0)").Scan(&totalTokens)
	h.db.DB().Model(&model.UsageRecord{}).Where("created_at >= ? AND status = ?", since, "error").Count(&errorCount)
	activeKeys := len(h.cache.ListIngressKeys())
	errorRate := 0.0
	if totalRequests > 0 {
		errorRate = float64(errorCount) / float64(totalRequests)
	}
	c.JSON(http.StatusOK, gin.H{
		"total_requests_24h": totalRequests,
		"total_tokens_24h":   totalTokens,
		"error_rate":         errorRate,
		"active_ingress_keys": activeKeys,
		"providers":          len(h.cache.ListProviders()),
	})
}

func (h *Handler) DashboardProviders(c *gin.Context) {
	providers := h.cache.ListProviders()
	health := h.cache.GetHealthStatus()
	type item struct {
		model.Provider
		Health model.HealthCheckRecord `json:"health"`
	}
	var out []item
	for _, p := range providers {
		out = append(out, item{Provider: p, Health: health[p.ID]})
	}
	c.JSON(http.StatusOK, gin.H{"data": out})
}

func (h *Handler) DashboardIngressUsage(c *gin.Context) {
	keys := h.cache.ListIngressKeys()
	c.JSON(http.StatusOK, gin.H{"data": keys})
}

func (h *Handler) DashboardEgressUsage(c *gin.Context) {
	keys := h.cache.ListAllProviderKeys()
	c.JSON(http.StatusOK, gin.H{"data": keys})
}

func (h *Handler) DashboardProviderModelUsage(c *gin.Context) {
	since := time.Now().Add(-24 * time.Hour)
	type row struct {
		ProviderID   uint    `json:"provider_id"`
		Model        string  `json:"model"`
		RequestCount int64   `json:"request_count"`
		TokenCount   int64   `json:"token_count"`
		Cost         float64 `json:"cost"`
	}
	var rows []row
	h.db.DB().Model(&model.UsageRecord{}).
		Select("provider_id, model, COUNT(*) as request_count, COALESCE(SUM(tokens_in + tokens_out), 0) as token_count, COALESCE(SUM(cost), 0) as cost").
		Where("created_at >= ? AND provider_id > 0 AND model != ''", since).
		Group("provider_id, model").
		Order("request_count desc").
		Limit(50).
		Scan(&rows)

	type item struct {
		ProviderID   uint    `json:"provider_id"`
		ProviderName string  `json:"provider_name"`
		Model        string  `json:"model"`
		RequestCount int64   `json:"request_count"`
		TokenCount   int64   `json:"token_count"`
		Cost         float64 `json:"cost"`
	}
	out := make([]item, 0, len(rows))
	for _, r := range rows {
		name := ""
		if p, ok := h.cache.GetProvider(r.ProviderID); ok {
			name = p.Name
		}
		out = append(out, item{
			ProviderID:   r.ProviderID,
			ProviderName: name,
			Model:        r.Model,
			RequestCount: r.RequestCount,
			TokenCount:   r.TokenCount,
			Cost:         r.Cost,
		})
	}
	c.JSON(http.StatusOK, gin.H{"data": out})
}

func (h *Handler) DashboardClientIPUsage(c *gin.Context) {
	since := time.Now().Add(-24 * time.Hour)
	type item struct {
		ClientIP     string  `json:"client_ip"`
		RequestCount int64   `json:"request_count"`
		TokenCount   int64   `json:"token_count"`
		Cost         float64 `json:"cost"`
	}
	var out []item
	h.db.DB().Model(&model.UsageRecord{}).
		Select("client_ip, COUNT(*) as request_count, COALESCE(SUM(tokens_in + tokens_out), 0) as token_count, COALESCE(SUM(cost), 0) as cost").
		Where("created_at >= ? AND client_ip != ''", since).
		Group("client_ip").
		Order("request_count desc").
		Limit(50).
		Scan(&out)
	c.JSON(http.StatusOK, gin.H{"data": out})
}

func (h *Handler) DashboardRequestTrend(c *gin.Context) {
	since := time.Now().Add(-23 * time.Hour).Truncate(time.Hour)
	type aggRow struct {
		Hour     string `gorm:"column:hour"`
		Requests int64  `gorm:"column:requests"`
		Errors   int64  `gorm:"column:errors"`
		Tokens   int64  `gorm:"column:tokens"`
	}
	var rows []aggRow
	h.db.DB().Model(&model.UsageRecord{}).
		Select(`strftime('%Y-%m-%d %H:00', created_at) as hour,
			COUNT(*) as requests,
			SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END) as errors,
			COALESCE(SUM(tokens_in + tokens_out), 0) as tokens`).
		Where("created_at >= ?", since).
		Group("hour").
		Order("hour").
		Scan(&rows)

	byHour := make(map[string]aggRow, len(rows))
	for _, r := range rows {
		byHour[r.Hour] = r
	}

	type bucket struct {
		Hour     string `json:"hour"`
		Requests int64  `json:"requests"`
		Errors   int64  `json:"errors"`
		Tokens   int64  `json:"tokens"`
	}
	out := make([]bucket, 24)
	for i := 0; i < 24; i++ {
		t := since.Add(time.Duration(i) * time.Hour)
		key := t.Format("2006-01-02 15:00")
		if r, ok := byHour[key]; ok {
			out[i] = bucket{Hour: key, Requests: r.Requests, Errors: r.Errors, Tokens: r.Tokens}
		} else {
			out[i] = bucket{Hour: key}
		}
	}
	c.JSON(http.StatusOK, gin.H{"data": out})
}
