package admin_agent

import (
	"context"
	"sort"

	"jnc-server/app/main/api/internal/svc"
	"jnc-server/app/main/api/internal/types"
	"jnc-server/common/globalkey"
	"jnc-server/pkg/lzkit/crypto"

	"github.com/pkg/errors"
	"github.com/zeromicro/go-zero/core/logx"
)

type AdminGetAgentRankingLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewAdminGetAgentRankingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentRankingLogic {
	return &AdminGetAgentRankingLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *AdminGetAgentRankingLogic) AdminGetAgentRanking(req *types.AdminGetAgentRankingReq) (resp *types.AdminGetAgentRankingResp, err error) {
	// Set default limit if not provided
	limit := req.Limit
	if limit <= 0 {
		limit = 10
	}

	// Validate type parameter
	if req.Type != "commission" && req.Type != "orders" {
		return nil, errors.New("invalid type parameter, must be 'commission' or 'orders'")
	}

	var items []types.AgentRankingItem

	if req.Type == "commission" {
		// Rank by sum of commission amounts
		items, err = l.queryCommissionRanking(int(limit))
		if err != nil {
			return nil, err
		}
	} else {
		// Rank by count of orders
		items, err = l.queryOrdersRanking(int(limit))
		if err != nil {
			return nil, err
		}
	}

	resp = &types.AdminGetAgentRankingResp{
		Items: items,
	}

	return resp, nil
}

// queryCommissionRanking queries top agents by total commission amount
func (l *AdminGetAgentRankingLogic) queryCommissionRanking(limit int) ([]types.AgentRankingItem, error) {
	// 1. Query all commissions
	builder := l.svcCtx.AgentCommissionModel.SelectBuilder()
	builder = builder.Where("del_state = ?", globalkey.DelStateNo)

	commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, builder, "")
	if err != nil {
		return nil, err
	}

	// 2. Group by agent_id and sum amounts
	agentCommissionMap := make(map[string]float64)
	for _, commission := range commissions {
		agentCommissionMap[commission.AgentId] += commission.Amount
	}

	// 3. Build agent stats
	type AgentStat struct {
		AgentID string
		Amount  float64
	}

	stats := make([]AgentStat, 0, len(agentCommissionMap))
	for agentID, amount := range agentCommissionMap {
		stats = append(stats, AgentStat{
			AgentID: agentID,
			Amount:  amount,
		})
	}

	// 4. Sort by amount descending
	sort.Slice(stats, func(i, j int) bool {
		return stats[i].Amount > stats[j].Amount
	})

	// 5. Apply limit
	if limit > len(stats) {
		limit = len(stats)
	}
	stats = stats[:limit]

	// 6. Query agents and build response
	agentIDs := make([]string, len(stats))
	for i, stat := range stats {
		agentIDs[i] = stat.AgentID
	}

	agents, err := l.svcCtx.AgentModel.FindAll(l.ctx,
		l.svcCtx.AgentModel.SelectBuilder().Where("del_state = ?", globalkey.DelStateNo), "")
	if err != nil {
		return nil, err
	}

	// Build agent map
	agentMap := make(map[string]*struct {
		Mobile string
		Region string
	})
	for _, agent := range agents {
		region := "未知"
		if agent.Region.Valid && agent.Region.String != "" {
			region = agent.Region.String
		}
		agentMap[agent.Id] = &struct {
			Mobile string
			Region string
		}{
			Mobile: agent.Mobile,
			Region: region,
		}
	}

	// 7. Build items
	items := make([]types.AgentRankingItem, len(stats))
	for i, stat := range stats {
		agentInfo := agentMap[stat.AgentID]

		// Decrypt mobile
		decryptedMobile, err := crypto.DecryptMobile(agentInfo.Mobile, l.svcCtx.Config.Encrypt.SecretKey)
		if err != nil {
			l.Errorf("Failed to decrypt mobile for agent %s: %v", stat.AgentID, err)
			decryptedMobile = ""
		}

		items[i] = types.AgentRankingItem{
			AgentId:     stat.AgentID,
			AgentMobile: decryptedMobile,
			Region:      agentInfo.Region,
			Value:       stat.Amount,
		}
	}

	return items, nil
}

// queryOrdersRanking queries top agents by order count
func (l *AdminGetAgentRankingLogic) queryOrdersRanking(limit int) ([]types.AgentRankingItem, error) {
	// 1. Query all orders
	builder := l.svcCtx.AgentOrderModel.SelectBuilder()
	builder = builder.Where("del_state = ?", globalkey.DelStateNo)

	orders, err := l.svcCtx.AgentOrderModel.FindAll(l.ctx, builder, "")
	if err != nil {
		return nil, err
	}

	// 2. Group by agent_id and count
	agentOrderCountMap := make(map[string]int64)
	for _, order := range orders {
		agentOrderCountMap[order.AgentId]++
	}

	// 3. Build agent stats
	type AgentStat struct {
		AgentID string
		Count   int64
	}

	stats := make([]AgentStat, 0, len(agentOrderCountMap))
	for agentID, count := range agentOrderCountMap {
		stats = append(stats, AgentStat{
			AgentID: agentID,
			Count:   count,
		})
	}

	// 4. Sort by count descending
	sort.Slice(stats, func(i, j int) bool {
		return stats[i].Count > stats[j].Count
	})

	// 5. Apply limit
	if limit > len(stats) {
		limit = len(stats)
	}
	stats = stats[:limit]

	// 6. Query agents
	agentIDs := make([]string, len(stats))
	for i, stat := range stats {
		agentIDs[i] = stat.AgentID
	}

	agents, err := l.svcCtx.AgentModel.FindAll(l.ctx,
		l.svcCtx.AgentModel.SelectBuilder().Where("del_state = ?", globalkey.DelStateNo), "")
	if err != nil {
		return nil, err
	}

	// Build agent map
	agentMap := make(map[string]*struct {
		Mobile string
		Region string
	})
	for _, agent := range agents {
		region := "未知"
		if agent.Region.Valid && agent.Region.String != "" {
			region = agent.Region.String
		}
		agentMap[agent.Id] = &struct {
			Mobile string
			Region string
		}{
			Mobile: agent.Mobile,
			Region: region,
		}
	}

	// 7. Build items
	items := make([]types.AgentRankingItem, len(stats))
	for i, stat := range stats {
		agentInfo := agentMap[stat.AgentID]

		// Decrypt mobile
		decryptedMobile, err := crypto.DecryptMobile(agentInfo.Mobile, l.svcCtx.Config.Encrypt.SecretKey)
		if err != nil {
			l.Errorf("Failed to decrypt mobile for agent %s: %v", stat.AgentID, err)
			decryptedMobile = ""
		}

		items[i] = types.AgentRankingItem{
			AgentId:     stat.AgentID,
			AgentMobile: decryptedMobile,
			Region:      agentInfo.Region,
			Value:       float64(stat.Count),
		}
	}

	return items, nil
}
