package admin

import (
	"net/http"
	"strconv"
	"time"

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

func (h *Handler) ListRoutingRules(c *gin.Context) {
	ingressID := parseUint(c.Param("id"))
	c.JSON(http.StatusOK, gin.H{"data": h.cache.ListRoutingRules(ingressID)})
}

func (h *Handler) CreateRoutingRule(c *gin.Context) {
	ingressID := parseUint(c.Param("id"))
	var req struct {
		ModelPattern  string `json:"model_pattern"`
		ProviderID    uint   `json:"provider_id"`
		ProviderKeyID uint   `json:"provider_key_id"`
		Priority      int    `json:"priority"`
		Enabled       *bool  `json:"enabled"`
	}
	if err := c.ShouldBindJSON(&req); err != nil || req.ModelPattern == "" || req.ProviderID == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
		return
	}
	rule := model.RoutingRule{
		IngressKeyID:  ingressID,
		ModelPattern:  req.ModelPattern,
		ProviderID:    req.ProviderID,
		ProviderKeyID: req.ProviderKeyID,
		Priority:      req.Priority,
		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.ListRoutingRules(ingressID)
	rules = append(rules, rule)
	h.cache.SetRoutingRules(ingressID, rules)
	c.JSON(http.StatusCreated, rule)
}

func (h *Handler) UpdateRoutingRule(c *gin.Context) {
	ruleID := parseUint(c.Param("ruleId"))
	var rule model.RoutingRule
	if err := h.db.DB().First(&rule, ruleID).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
		return
	}
	var req struct {
		ModelPattern  string `json:"model_pattern"`
		ProviderID    uint   `json:"provider_id"`
		ProviderKeyID uint   `json:"provider_key_id"`
		Priority      int    `json:"priority"`
		Enabled       *bool  `json:"enabled"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
		return
	}
	if req.ModelPattern != "" {
		rule.ModelPattern = req.ModelPattern
	}
	if req.ProviderID > 0 {
		rule.ProviderID = req.ProviderID
	}
	if req.ProviderKeyID >= 0 {
		rule.ProviderKeyID = req.ProviderKeyID
	}
	rule.Priority = req.Priority
	if req.Enabled != nil {
		rule.Enabled = *req.Enabled
	}
	h.db.DB().Save(&rule)
	h.reloadRoutingRules(rule.IngressKeyID)
	c.JSON(http.StatusOK, rule)
}

func (h *Handler) DeleteRoutingRule(c *gin.Context) {
	ruleID := parseUint(c.Param("ruleId"))
	var rule model.RoutingRule
	if err := h.db.DB().First(&rule, ruleID).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
		return
	}
	h.db.DB().Delete(&rule)
	h.reloadRoutingRules(rule.IngressKeyID)
	c.JSON(http.StatusOK, gin.H{"ok": true})
}

func (h *Handler) reloadRoutingRules(ingressID uint) {
	var rules []model.RoutingRule
	h.db.DB().Where("ingress_key_id = ?", ingressID).Find(&rules)
	h.cache.SetRoutingRules(ingressID, rules)
}

func (h *Handler) ListRequestLogs(c *gin.Context) {
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
	if page < 1 {
		page = 1
	}
	if pageSize <= 0 || pageSize > 50 {
		pageSize = 20
	}

	q := h.db.DB().Model(&model.UsageRecord{})
	if ingressID := c.Query("ingress_key_id"); ingressID != "" {
		q = q.Where("ingress_key_id = ?", ingressID)
	}
	if status := c.Query("status"); status != "" {
		q = q.Where("status = ?", status)
	}
	if endpoint := c.Query("endpoint"); endpoint != "" {
		q = q.Where("endpoint = ?", endpoint)
	}
	if clientIP := c.Query("client_ip"); clientIP != "" {
		q = q.Where("client_ip LIKE ?", "%"+clientIP+"%")
	}
	if modelName := c.Query("model"); modelName != "" {
		q = q.Where("model LIKE ?", "%"+modelName+"%")
	}

	var total int64
	q.Count(&total)

	var logs []model.UsageRecord
	q.Order("created_at desc").
		Offset((page - 1) * pageSize).
		Limit(pageSize).
		Find(&logs)

	type item struct {
		ID           uint      `json:"id"`
		IngressKeyID uint      `json:"ingress_key_id"`
		IngressName  string    `json:"ingress_name"`
		ClientIP     string    `json:"client_ip"`
		Endpoint     string    `json:"endpoint"`
		Model        string    `json:"model"`
		LatencyMs    int64     `json:"latency_ms"`
		Status       string    `json:"status"`
		Stream       bool      `json:"stream"`
		ErrorMsg     string    `json:"error_msg"`
		CreatedAt    time.Time `json:"created_at"`
	}
	out := make([]item, 0, len(logs))
	for _, log := range logs {
		name := ""
		if log.Endpoint == model.EndpointAdminLogin {
			name = "管理台"
		} else if k, ok := h.cache.GetIngressKey(log.IngressKeyID); ok {
			name = k.Name
		}
		out = append(out, item{
			ID:           log.ID,
			IngressKeyID: log.IngressKeyID,
			IngressName:  name,
			ClientIP:     log.ClientIP,
			Endpoint:     log.Endpoint,
			Model:        log.Model,
			LatencyMs:    log.LatencyMs,
			Status:       log.Status,
			Stream:       log.Stream,
			ErrorMsg:     log.ErrorMsg,
			CreatedAt:    log.CreatedAt,
		})
	}
	c.JSON(http.StatusOK, gin.H{
		"data":      out,
		"total":     total,
		"page":      page,
		"page_size": pageSize,
		"max_kept":  model.MaxUsageLogRecords,
	})
}

func (h *Handler) GetRequestLog(c *gin.Context) {
	id := parseUint(c.Param("id"))
	var log model.UsageRecord
	if err := h.db.DB().First(&log, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
		return
	}
	name := ""
	if log.Endpoint == model.EndpointAdminLogin {
		name = "管理台"
	} else if k, ok := h.cache.GetIngressKey(log.IngressKeyID); ok {
		name = k.Name
	}
	c.JSON(http.StatusOK, gin.H{
		"data": gin.H{
			"id":            log.ID,
			"ingress_key_id": log.IngressKeyID,
			"ingress_name":  name,
			"client_ip":     log.ClientIP,
			"endpoint":      log.Endpoint,
			"model":         log.Model,
			"latency_ms":    log.LatencyMs,
			"status":        log.Status,
			"stream":        log.Stream,
			"error_msg":     log.ErrorMsg,
			"request_body":  log.RequestBody,
			"response_body": log.ResponseBody,
			"created_at":    log.CreatedAt,
		},
	})
}

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