package usage

import (
	"context"
	"errors"

	usageDomain "apps/backend/internal/module/usage/domain"
	usageUC "apps/backend/internal/module/usage/usecase"
	"apps/backend/internal/response"
	"apps/backend/internal/svc"
	"apps/backend/internal/types"

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

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

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

func (l *GetTenantUsageAnalyticsLogic) GetTenantUsageAnalytics(req *types.UsageTenantAnalyticsReq) (resp *types.UsageTenantAnalyticsData, err error) {
	if l.svcCtx.Usage == nil || l.svcCtx.Members == nil {
		return nil, response.Biz(503, 503001, "usage not configured")
	}
	query, err := usageUC.ParseAnalyticsQuery(req.Granularity, req.From, req.To)
	if err != nil {
		if errors.Is(err, usageDomain.ErrInvalidRange) {
			return nil, response.Biz(400, 400001, err.Error())
		}
		return nil, err
	}
	memberList, err := l.svcCtx.Members.ListAllMembers(l.ctx)
	if err != nil {
		return nil, err
	}
	members := make([]usageDomain.AnalyticsMember, 0, len(memberList))
	for _, member := range memberList {
		members = append(members, usageDomain.AnalyticsMember{
			UID: member.UID, Email: member.Email, DisplayName: member.DisplayName,
		})
	}
	analytics, err := l.svcCtx.Usage.TenantAnalytics(l.ctx, query, members)
	if err != nil {
		return nil, err
	}

	byMeter := make(map[string]types.UsageMeterCount, len(analytics.ByMeter))
	for meter, count := range analytics.ByMeter {
		byMeter[meter] = types.UsageMeterCount{Count: count.Count, Credits: count.Credits}
	}
	byokMeter := make(map[string]types.UsageMeterCount, len(analytics.Byok.ByMeter))
	for meter, count := range analytics.Byok.ByMeter {
		byokMeter[meter] = types.UsageMeterCount{Count: count.Count, Credits: count.Credits}
	}
	series := make([]types.UsageTenantAnalyticsBucket, 0, len(analytics.Series))
	for _, bucket := range analytics.Series {
		series = append(series, types.UsageTenantAnalyticsBucket{
			Key: bucket.Key, Label: bucket.Label, PurchasedCredits: bucket.PurchasedCredits,
			ConsumedCredits: bucket.ConsumedCredits, AiCalls: bucket.AICalls,
			SearchCalls: bucket.SearchCalls, ByokCallCount: bucket.ByokCallCount,
		})
	}
	rows := make([]types.UsageTenantAnalyticsMember, 0, len(analytics.Members))
	for _, member := range analytics.Members {
		rows = append(rows, types.UsageTenantAnalyticsMember{
			Uid: member.UID, Email: member.Email, DisplayName: member.DisplayName,
			Unlimited: member.Unlimited, PlanId: member.PlanID,
			PurchasedCredits: member.PurchasedCredits, TotalCredits: member.TotalCredits,
			AiCalls: member.AICalls, SearchCalls: member.SearchCalls,
			ByokCallCount: member.ByokCallCount, RemainingCredits: member.RemainingCredits, Pct: member.Pct,
		})
	}
	return &types.UsageTenantAnalyticsData{
		Granularity: analytics.Granularity, From: analytics.From, To: analytics.To,
		RangeLabel: analytics.RangeLabel, PurchasedCredits: analytics.PurchasedCredits,
		ConsumedCredits: analytics.ConsumedCredits, RemainingCredits: analytics.RemainingCredits,
		Pct: analytics.Pct, AiCalls: analytics.AICalls, SearchCalls: analytics.SearchCalls,
		ByMeter: byMeter, Byok: types.UsageByokBlock{CallCount: analytics.Byok.CallCount, ByMeter: byokMeter},
		Series: series, Members: rows,
	}, nil
}
