package server

import (
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

type UsagePeriodFilter struct {
	Period string `form:"period"`
	From   string `form:"from"`
	To     string `form:"to"`
}

func (f *UsagePeriodFilter) ToSQL() (string, []interface{}) {
	period := f.Period
	if period == "" {
		period = "all"
	}

	if period == "custom" {
		var clauses []string
		var binds []interface{}
		if f.From != "" {
			clauses = append(clauses, "timestamp >= ?")
			binds = append(binds, f.From)
		}
		if f.To != "" {
			clauses = append(clauses, "timestamp <= ?")
			binds = append(binds, f.To)
		}
		if len(clauses) > 0 {
			return " AND " + strings.Join(clauses, " AND "), binds
		}
		return "", nil
	}

	now := time.Now().UTC()
	var cutoff time.Time
	switch period {
	case "today":
		cutoff = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
	case "24h":
		cutoff = now.Add(-24 * time.Hour)
	case "7d":
		cutoff = now.Add(-7 * 24 * time.Hour)
	case "30d":
		cutoff = now.Add(-30 * 24 * time.Hour)
	default:
		return "", nil
	}

	return " AND timestamp >= ?", []interface{}{cutoff.Format(time.RFC3339)}
}

func (s *Server) handleUsageSummary(c *gin.Context) {
	var filter UsagePeriodFilter
	if err := c.ShouldBindQuery(&filter); err != nil {
		// ignore
	}

	clause, binds := filter.ToSQL()

	// Total stats
	var totalStats struct {
		TotalRequests    int     `db:"total_requests"`
		TotalTokens      int     `db:"total_tokens"`
		CacheReadTokens  int     `db:"total_cache_read_tokens"`
		CacheWriteTokens int     `db:"total_cache_write_tokens"`
		TotalCost        float64 `db:"total_cost"`
		ActiveClients    int     `db:"active_clients"`
	}
	err := s.database.Get(&totalStats, fmt.Sprintf(`
		SELECT 
			COUNT(*) as total_requests,
			COALESCE(SUM(total_tokens), 0) as total_tokens,
			COALESCE(SUM(cache_read_tokens), 0) as total_cache_read_tokens,
			COALESCE(SUM(cache_write_tokens), 0) as total_cache_write_tokens,
			COALESCE(SUM(cost), 0.0) as total_cost,
			COUNT(DISTINCT client_id) as active_clients
		FROM llm_requests
		WHERE 1=1 %s
	`, clause), binds...)
	if err != nil {
		c.JSON(http.StatusInternalServerError, ErrorResponse(err.Error()))
		return
	}

	// Today stats
	var todayStats struct {
		TodayRequests int     `db:"today_requests"`
		TodayCost     float64 `db:"today_cost"`
	}
	today := time.Now().UTC().Format("2006-01-02")
	err = s.database.Get(&todayStats, `
		SELECT 
			COUNT(*) as today_requests,
			COALESCE(SUM(cost), 0.0) as today_cost
		FROM llm_requests
		WHERE timestamp LIKE ?
	`, today+"%")
	if err != nil {
		todayStats.TodayRequests = 0
		todayStats.TodayCost = 0.0
	}

	// Error rate & Avg response time
	var miscStats struct {
		ErrorRate       float64 `db:"error_rate"`
		AvgResponseTime float64 `db:"avg_response_time"`
	}
	err = s.database.Get(&miscStats, `
		SELECT 
			CASE WHEN COUNT(*) = 0 THEN 0.0 ELSE (CAST(SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END) AS FLOAT) / COUNT(*)) * 100.0 END as error_rate,
			COALESCE(AVG(duration_ms), 0.0) as avg_response_time
		FROM llm_requests
	`)
	if err != nil {
		miscStats.ErrorRate = 0.0
		miscStats.AvgResponseTime = 0.0
	}

	c.JSON(http.StatusOK, SuccessResponse(gin.H{
		"total_requests":           totalStats.TotalRequests,
		"total_tokens":             totalStats.TotalTokens,
		"total_cache_read_tokens":  totalStats.CacheReadTokens,
		"total_cache_write_tokens": totalStats.CacheWriteTokens,
		"total_cost":               totalStats.TotalCost,
		"active_clients":           totalStats.ActiveClients,
		"today_requests":           todayStats.TodayRequests,
		"today_cost":               todayStats.TodayCost,
		"error_rate":               miscStats.ErrorRate,
		"avg_response_time":        miscStats.AvgResponseTime,
	}))
}

func (s *Server) handleTimeSeries(c *gin.Context) {
	var filter UsagePeriodFilter
	if err := c.ShouldBindQuery(&filter); err != nil {
		// ignore
	}

	clause, binds := filter.ToSQL()

	if clause == "" {
		cutoff := time.Now().UTC().Add(-30 * 24 * time.Hour)
		clause = " AND timestamp >= ?"
		binds = []interface{}{cutoff.Format(time.RFC3339)}
	}

	query := fmt.Sprintf(`
		SELECT 
			COALESCE(SUBSTR(timestamp, 1, 10), 'unknown') as bucket,
			COUNT(*) as requests,
			COALESCE(SUM(total_tokens), 0) as tokens,
			COALESCE(SUM(cost), 0.0) as cost
		FROM llm_requests
		WHERE 1=1 %s
		GROUP BY bucket
		ORDER BY bucket
	`, clause)

	rows, err := s.database.Queryx(query, binds...)
	if err != nil {
		c.JSON(http.StatusInternalServerError, ErrorResponse(err.Error()))
		return
	}
	defer rows.Close()

	var series []gin.H
	for rows.Next() {
		var bucket string
		var requests int
		var tokens int
		var cost float64
		if err := rows.Scan(&bucket, &requests, &tokens, &cost); err != nil {
			continue
		}
		series = append(series, gin.H{
			"time":     bucket,
			"requests": requests,
			"tokens":   tokens,
			"cost":     cost,
		})
	}

	granularity := "day"
	c.JSON(http.StatusOK, SuccessResponse(gin.H{
		"series":      series,
		"granularity": granularity,
	}))
}

func (s *Server) handleProvidersUsage(c *gin.Context) {
	var filter UsagePeriodFilter
	if err := c.ShouldBindQuery(&filter); err != nil {
		// ignore
	}

	clause, binds := filter.ToSQL()

	rows, err := s.database.Queryx(fmt.Sprintf(`
		SELECT 
			COALESCE(provider, 'unknown') as provider, 
			COUNT(*) as requests,
			COALESCE(SUM(cost), 0.0) as cost
		FROM llm_requests
		WHERE 1=1 %s
		GROUP BY provider
	`, clause), binds...)
	if err != nil {
		c.JSON(http.StatusOK, SuccessResponse([]interface{}{}))
		return
	}
	defer rows.Close()

	var results []gin.H
	for rows.Next() {
		var provider string
		var requests int
		var cost float64
		if err := rows.Scan(&provider, &requests, &cost); err == nil {
			results = append(results, gin.H{"provider": provider, "requests": requests, "cost": cost})
		}
	}

	c.JSON(http.StatusOK, SuccessResponse(results))
}

func (s *Server) handleClientsUsage(c *gin.Context) {
	var filter UsagePeriodFilter
	if err := c.ShouldBindQuery(&filter); err != nil {
		// ignore
	}

	clause, binds := filter.ToSQL()

	rows, err := s.database.Queryx(fmt.Sprintf(`
		SELECT COALESCE(client_id, 'unknown') as client_id, COUNT(*) as requests
		FROM llm_requests
		WHERE 1=1 %s
		GROUP BY client_id
	`, clause), binds...)
	if err != nil {
		c.JSON(http.StatusOK, SuccessResponse([]interface{}{}))
		return
	}
	defer rows.Close()

	var results []gin.H
	for rows.Next() {
		var clientID string
		var requests int
		if err := rows.Scan(&clientID, &requests); err == nil {
			results = append(results, gin.H{"client_id": clientID, "requests": requests})
		}
	}

	c.JSON(http.StatusOK, SuccessResponse(results))
}

func (s *Server) handleAnalyticsBreakdown(c *gin.Context) {
	var filter UsagePeriodFilter
	if err := c.ShouldBindQuery(&filter); err != nil {
		// ignore
	}

	clause, binds := filter.ToSQL()

	// Models breakdown
	var models []struct {
		Label string `json:"label"`
		Value int    `json:"value"`
	}
	mRows, err := s.database.Queryx(fmt.Sprintf("SELECT COALESCE(model, 'unknown') as label, COUNT(*) as value FROM llm_requests WHERE 1=1 %s GROUP BY model ORDER BY value DESC", clause), binds...)
	if err == nil {
		for mRows.Next() {
			var label string
			var value int
			if err := mRows.Scan(&label, &value); err == nil {
				models = append(models, struct {
					Label string `json:"label"`
					Value int    `json:"value"`
				}{label, value})
			}
		}
		mRows.Close()
	}

	// Clients breakdown
	var clients []struct {
		Label string `json:"label"`
		Value int    `json:"value"`
	}
	cRows, err := s.database.Queryx(fmt.Sprintf("SELECT COALESCE(client_id, 'unknown') as label, COUNT(*) as value FROM llm_requests WHERE 1=1 %s GROUP BY client_id ORDER BY value DESC", clause), binds...)
	if err == nil {
		for cRows.Next() {
			var label string
			var value int
			if err := cRows.Scan(&label, &value); err == nil {
				clients = append(clients, struct {
					Label string `json:"label"`
					Value int    `json:"value"`
				}{label, value})
			}
		}
		cRows.Close()
	}

	c.JSON(http.StatusOK, SuccessResponse(gin.H{
		"models":  models,
		"clients": clients,
	}))
}

func (s *Server) handleDetailedUsage(c *gin.Context) {
	var filter UsagePeriodFilter
	if err := c.ShouldBindQuery(&filter); err != nil {
		// ignore
	}

	clause, binds := filter.ToSQL()

	query := fmt.Sprintf(`
		SELECT 
			COALESCE(SUBSTR(timestamp, 1, 10), 'unknown') as date,
			COALESCE(client_id, 'unknown') as client,
			COALESCE(provider, 'unknown') as provider,
			COALESCE(model, 'unknown') as model,
			COUNT(*) as requests,
			COALESCE(SUM(total_tokens), 0) as tokens,
			COALESCE(SUM(cache_read_tokens), 0) as cache_read_tokens,
			COALESCE(SUM(cache_write_tokens), 0) as cache_write_tokens,
			COALESCE(SUM(cost), 0.0) as cost
		FROM llm_requests
		WHERE 1=1 %s
		GROUP BY date, client, provider, model
		ORDER BY date DESC, cost DESC
	`, clause)

	rows, err := s.database.Queryx(query, binds...)
	if err != nil {
		c.JSON(http.StatusOK, SuccessResponse([]interface{}{}))
		return
	}
	defer rows.Close()

	var results []gin.H
	for rows.Next() {
		var date, client, provider, model string
		var requests, tokens, cacheRead, cacheWrite int
		var cost float64
		if err := rows.Scan(&date, &client, &provider, &model, &requests, &tokens, &cacheRead, &cacheWrite, &cost); err == nil {
			results = append(results, gin.H{
				"date":               date,
				"client":             client,
				"provider":           provider,
				"model":              model,
				"requests":           requests,
				"tokens":             tokens,
				"cache_read_tokens":  cacheRead,
				"cache_write_tokens": cacheWrite,
				"cost":               cost,
			})
		}
	}

	c.JSON(http.StatusOK, SuccessResponse(results))
}
