package handler

import (
	"fmt"
	"strconv"
	"time"
	"xboard-go/internal/database"
	"xboard-go/internal/model"

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

// AdminGetTrafficRank returns traffic ranking for nodes or users.
func AdminGetTrafficRank(c *gin.Context) {
	rankType := c.Query("type") // node or user
	startTimeStr := c.Query("start_time")
	endTimeStr := c.Query("end_time")

	startTime, _ := strconv.ParseInt(startTimeStr, 10, 64)
	endTime, _ := strconv.ParseInt(endTimeStr, 10, 64)

	if startTime == 0 {
		startTime = time.Now().AddDate(0, 0, -7).Unix()
	}
	if endTime == 0 {
		endTime = time.Now().Unix()
	}
	periodDuration := endTime - startTime
	if periodDuration <= 0 {
		periodDuration = 86400
	}
	previousStart := startTime - periodDuration
	previousEnd := startTime

	var result []gin.H
	if rankType == "user" {
		type userRank struct {
			ID    int   `json:"id"`
			Value int64 `json:"value"`
		}
		var ranks []userRank
		database.DB.Model(&model.StatUser{}).
			Select("user_id as id, SUM(u + d) as value").
			Where("record_at >= ? AND record_at <= ?", startTime, endTime).
			Group("user_id").
			Order("value DESC").
			Limit(10).
			Scan(&ranks)

		var userIDs []int
		for _, r := range ranks {
			userIDs = append(userIDs, r.ID)
		}
		userEmails := loadUserEmailMap(userIDs)
		previousValues := loadUserPreviousTrafficMap(userIDs, previousStart, previousEnd)
		for _, r := range ranks {
			previousValue := previousValues[r.ID]
			result = append(result, gin.H{
				"id":            fmt.Sprintf("%d", r.ID),
				"name":          userEmails[r.ID],
				"value":         r.Value,
				"previousValue": previousValue,
				"change":        calculateGrowth(r.Value, previousValue),
			})
		}
	} else {
		// Default to node
		type nodeRank struct {
			ID    int    `json:"id"`
			Value int64  `json:"value"`
			Name  string `json:"name"`
		}
		var ranks []nodeRank
		database.DB.Model(&model.StatServer{}).
			Select("server_id as id, SUM(u + d) as value").
			Where("record_at >= ? AND record_at <= ?", startTime, endTime).
			Group("server_id").
			Order("value DESC").
			Limit(10).
			Scan(&ranks)

		var nodeIDs []int
		for _, r := range ranks {
			nodeIDs = append(nodeIDs, r.ID)
		}
		nodeNames := loadNodeNameMap(nodeIDs)
		previousValues := loadNodePreviousTrafficMap(nodeIDs, previousStart, previousEnd)
		for _, r := range ranks {
			previousValue := previousValues[r.ID]
			result = append(result, gin.H{
				"id":            fmt.Sprintf("%d", r.ID),
				"name":          nodeNames[r.ID],
				"value":         r.Value,
				"previousValue": previousValue,
				"change":        calculateGrowth(r.Value, previousValue),
			})
		}
	}

	Success(c, result)
}

// AdminGetOrderStats returns order-related statistics for charts.
func AdminGetOrderStats(c *gin.Context) {
	startDateStr := c.Query("start_date")
	endDateStr := c.Query("end_date")
	statType := c.Query("type") // paid_total, paid_count, etc.

	var startDate int64
	var endDate int64

	if startDateStr != "" {
		t, _ := time.Parse("2006-01-02", startDateStr)
		startDate = t.Unix()
	} else {
		startDate = time.Now().AddDate(0, 0, -30).Truncate(24 * time.Hour).Unix()
	}

	if endDateStr != "" {
		t, _ := time.Parse("2006-01-02", endDateStr)
		endDate = t.Unix() + 86399
	} else {
		endDate = time.Now().Unix()
	}

	var stats []model.Stat
	database.DB.Where("record_at >= ? AND record_at <= ? AND record_type = ?", startDate, endDate, "d").
		Order("record_at ASC").
		Find(&stats)

	var list []gin.H
	var paidTotal int64
	var paidCount int64
	var commissionTotal int64
	var commissionCount int64
	for _, s := range stats {
		dateStr := time.Unix(s.RecordAt, 0).Format("2006-01-02")
		item := gin.H{
			"date": dateStr,
		}
		if statType != "" {
			item["value"] = getStatFieldValue(s, statType)
		} else {
			item["paid_total"] = s.PaidTotal
			item["paid_count"] = s.PaidCount
			item["commission_total"] = s.CommissionTotal
			item["commission_count"] = s.CommissionCount
		}
		paidTotal += s.PaidTotal
		paidCount += int64(s.PaidCount)
		commissionTotal += s.CommissionTotal
		commissionCount += int64(s.CommissionCount)
		list = append(list, item)
	}

	avgPaidAmount := int64(0)
	if paidCount > 0 {
		avgPaidAmount = paidTotal / paidCount
	}
	commissionRate := 0.0
	if paidTotal > 0 {
		commissionRate = float64(commissionTotal) / float64(paidTotal) * 100.0
	}

	Success(c, gin.H{
		"list": list,
		"summary": gin.H{
			"start_date":       time.Unix(startDate, 0).Format("2006-01-02"),
			"end_date":         time.Unix(endDate, 0).Format("2006-01-02"),
			"paid_total":       paidTotal,
			"paid_count":       paidCount,
			"avg_paid_amount":  avgPaidAmount,
			"commission_total": commissionTotal,
			"commission_count": commissionCount,
			"commission_rate":  commissionRate,
		},
	})
}

func loadUserPreviousTrafficMap(ids []int, startTime int64, endTime int64) map[int]int64 {
	result := make(map[int]int64)
	if len(ids) == 0 {
		return result
	}
	type userRank struct {
		ID    int   `json:"id"`
		Value int64 `json:"value"`
	}
	var ranks []userRank
	database.DB.Model(&model.StatUser{}).
		Select("user_id as id, SUM(u + d) as value").
		Where("user_id IN ? AND record_at >= ? AND record_at <= ?", ids, startTime, endTime).
		Group("user_id").
		Scan(&ranks)
	for _, rank := range ranks {
		result[rank.ID] = rank.Value
	}
	return result
}

func loadNodePreviousTrafficMap(ids []int, startTime int64, endTime int64) map[int]int64 {
	result := make(map[int]int64)
	if len(ids) == 0 {
		return result
	}
	type nodeRank struct {
		ID    int   `json:"id"`
		Value int64 `json:"value"`
	}
	var ranks []nodeRank
	database.DB.Model(&model.StatServer{}).
		Select("server_id as id, SUM(u + d) as value").
		Where("server_id IN ? AND record_at >= ? AND record_at <= ?", ids, startTime, endTime).
		Group("server_id").
		Scan(&ranks)
	for _, rank := range ranks {
		result[rank.ID] = rank.Value
	}
	return result
}

func loadNodeNameMap(ids []int) map[int]string {
	result := make(map[int]string)
	if len(ids) == 0 {
		return result
	}
	var servers []model.Server
	database.DB.Select("id", "name").Where("id IN ?", ids).Find(&servers)
	for _, s := range servers {
		result[s.ID] = s.Name
	}
	return result
}

func getStatFieldValue(s model.Stat, field string) any {
	switch field {
	case "paid_total":
		return s.PaidTotal
	case "paid_count":
		return s.PaidCount
	case "commission_total":
		return s.CommissionTotal
	case "commission_count":
		return s.CommissionCount
	case "register_count":
		return s.RegisterCount
	default:
		return 0
	}
}
