package userapi

import (
	"context"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"time"

	userv1 "hyapp.local/api/proto/user/v1"
	walletv1 "hyapp.local/api/proto/wallet/v1"
	"hyapp/pkg/appcode"
	"hyapp/services/gateway-service/internal/transport/http/httpkit"
)

type agencyRevenueStatsClient interface {
	GetAgencyHostGiftStats(context.Context, *walletv1.GetAgencyHostGiftStatsRequest) (*walletv1.GetAgencyHostGiftStatsResponse, error)
}

type agencyCenterStatsSummaryData struct {
	PolicyType                    string `json:"policy_type"`
	TotalEarnings                 string `json:"total_earnings"`
	GiftIncome                    string `json:"gift_income"`
	ShareIncome                   string `json:"share_income"`
	SalaryHostIncome              string `json:"salary_host_income"`
	PointDiamondHostIncome        string `json:"point_diamond_host_income"`
	PointDiamondAgencyShareIncome string `json:"point_diamond_agency_share_income"`
	TotalHosts                    int    `json:"total_hosts"`
	GiftedHostCount               int64  `json:"gifted_host_count"`
}

type agencyCenterHostStatsData struct {
	MembershipID          string `json:"membership_id"`
	HostUserID            string `json:"host_user_id"`
	DisplayUserID         string `json:"display_user_id"`
	Username              string `json:"username"`
	Avatar                string `json:"avatar,omitempty"`
	JoinedAtMS            int64  `json:"joined_at_ms"`
	DiamondEarnings       string `json:"diamond_earnings"`
	DiamondExchanged      string `json:"diamond_exchanged"`
	SalaryDiamondEarnings string `json:"salary_diamond_earnings"`
	LegacyPointExchanged  string `json:"legacy_point_exchanged"`
	PointDiamondEarnings  string `json:"point_diamond_earnings"`
	PointDiamondExchanged string `json:"point_diamond_exchanged"`
	GiftSenders           int64  `json:"gift_senders"`
	OnlineDurationMS      int64  `json:"online_duration_ms"`
	ValidMicDurationMS    int64  `json:"valid_mic_duration_ms"`
	ValidMicDays          int64  `json:"valid_mic_days"`
	Removable             bool   `json:"removable"`
}

// getAgencyCenterStats 只做跨 owner 编排：成员关系/互动来自 user-service，金额和分成由
// wallet-service 一次批量返回；这里只对无法批量取得的互动统计使用有界并发。
func (h *Handler) getAgencyCenterStats(writer http.ResponseWriter, request *http.Request) {
	agency, ok := h.resolveCurrentOwnerAgency(writer, request)
	if !ok {
		return
	}
	revenueClient, revenueOK := h.walletClient.(agencyRevenueStatsClient)
	engagementClient, engagementOK := h.userHostClient.(hostEngagementStatsClient)
	if !revenueOK || !engagementOK {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	startDate, endDate, startAtMS, endAtMS, ok := parseHostCenterStatsRange(request)
	if !ok {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid date range")
		return
	}
	requestID := httpkit.RequestIDFromContext(request.Context())
	appCode := appcode.FromContext(request.Context())

	membersResp, err := h.userHostClient.GetAgencyMembers(request.Context(), &userv1.GetAgencyMembersRequest{
		Meta: httpkit.UserMeta(request, ""), AgencyId: agency.GetAgencyId(), Status: membershipStatusActive,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	policyResp, err := h.walletClient.GetActiveHostSalaryPolicy(request.Context(), &walletv1.GetActiveHostSalaryPolicyRequest{
		RequestId: requestID, AppCode: appCode, RegionId: agency.GetRegionId(), CycleKey: time.Now().UTC().Format("2006-01"),
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	policyType := strings.TrimSpace(policyResp.GetPolicy().GetPolicyType())
	memberships := make([]*userv1.AgencyMembership, 0, len(membersResp.GetMemberships()))
	userIDs := make([]int64, 0, len(membersResp.GetMemberships()))
	for _, membership := range membersResp.GetMemberships() {
		memberships = append(memberships, membership)
		userIDs = append(userIDs, membership.GetHostUserId())
	}
	profiles, err := h.userProfiles(request, userIDs)
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	giftResp, err := revenueClient.GetAgencyHostGiftStats(request.Context(), &walletv1.GetAgencyHostGiftStatsRequest{
		RequestId: requestID, AppCode: appCode, HostUserIds: userIDs, AgencyUserId: agency.GetOwnerUserId(), StartAtMs: startAtMS, EndAtMs: endAtMS,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	hostRevenue := make(map[int64]*walletv1.HostRevenueStats, len(giftResp.GetHostStats()))
	for _, host := range giftResp.GetHostStats() {
		hostRevenue[host.GetHostUserId()] = host.GetStats()
	}

	items := make([]agencyCenterHostStatsData, len(memberships))
	ctx, cancel := context.WithCancel(request.Context())
	defer cancel()
	semaphore := make(chan struct{}, 8)
	var wait sync.WaitGroup
	var firstErr error
	var errorMu sync.Mutex
	for index, membership := range memberships {
		index, membership := index, membership
		wait.Add(1)
		go func() {
			defer wait.Done()
			semaphore <- struct{}{}
			defer func() { <-semaphore }()
			engagement, callErr := engagementClient.GetHostEngagementStats(ctx, &userv1.GetHostEngagementStatsRequest{
				Meta: httpkit.UserMeta(request, ""), HostUserId: membership.GetHostUserId(), StartAtMs: startAtMS, EndAtMs: endAtMS,
			})
			if callErr == nil {
				profile := profiles[membership.GetHostUserId()]
				revenue := hostRevenue[membership.GetHostUserId()]
				revenueMetrics := hostCenterRevenueMetrics(revenue, policyType)
				items[index] = agencyCenterHostStatsData{
					MembershipID: int64String(membership.GetMembershipId()), HostUserID: int64String(membership.GetHostUserId()),
					DisplayUserID: profile.DisplayUserID, Username: profile.Username, Avatar: profile.Avatar, JoinedAtMS: membership.GetJoinedAtMs(),
					DiamondEarnings: revenueMetrics.DiamondEarnings, DiamondExchanged: revenueMetrics.DiamondExchanged,
					SalaryDiamondEarnings: revenueMetrics.SalaryDiamondEarnings, LegacyPointExchanged: revenueMetrics.LegacyPointExchanged,
					PointDiamondEarnings: revenueMetrics.PointDiamondEarnings, PointDiamondExchanged: revenueMetrics.PointDiamondExchanged,
					GiftSenders:      revenue.GetGiftSenders(),
					OnlineDurationMS: engagement.GetStats().GetOnlineDurationMs(), ValidMicDurationMS: engagement.GetStats().GetValidMicDurationMs(), ValidMicDays: engagement.GetStats().GetValidMicDays(),
					Removable: membership.GetHostUserId() != agency.GetOwnerUserId() && membership.GetMembershipType() != membershipTypeOwner,
				}
			}
			if callErr != nil {
				errorMu.Lock()
				if firstErr == nil {
					firstErr = callErr
					cancel()
				}
				errorMu.Unlock()
			}
		}()
	}
	wait.Wait()
	if firstErr != nil {
		httpkit.WriteRPCError(writer, request, firstErr)
		return
	}
	httpkit.WriteOK(writer, request, map[string]any{
		"range":   hostCenterStatsRangeData{StartDate: startDate, EndDate: endDate, Timezone: "UTC"},
		"summary": agencyCenterSummaryFromGiftStats(giftResp.GetStats(), len(items), policyType),
		"hosts":   items,
	})
}

func agencyCenterSummaryFromGiftStats(stats *walletv1.AgencyHostGiftStats, totalHosts int, policyType string) agencyCenterStatsSummaryData {
	if stats == nil {
		return agencyCenterStatsSummaryData{
			TotalHosts: totalHosts, PolicyType: policyType,
			TotalEarnings: "0", GiftIncome: "0", ShareIncome: "0", SalaryHostIncome: "0",
			PointDiamondHostIncome: "0", PointDiamondAgencyShareIncome: "0",
		}
	}
	// POINT_DIAMOND 的 Agency 分成来自不可变送礼投影 agency_amount；SALARY_DIAMOND 不写该投影，
	// 因此不会把已结算 AGENCY_SALARY_USD 或通用钱包账变混进日期统计。
	giftIncome, shareIncome := stats.GetGiftIncome(), int64(0)
	if strings.EqualFold(strings.TrimSpace(policyType), "POINT_DIAMOND") {
		giftIncome, shareIncome = stats.GetPointDiamondHostIncome(), stats.GetPointDiamondAgencyShareIncome()
	}
	return agencyCenterStatsSummaryData{
		TotalEarnings: strconv.FormatInt(giftIncome+shareIncome, 10), GiftIncome: strconv.FormatInt(giftIncome, 10), ShareIncome: strconv.FormatInt(shareIncome, 10),
		PolicyType: policyType, SalaryHostIncome: strconv.FormatInt(stats.GetGiftIncome(), 10),
		PointDiamondHostIncome: strconv.FormatInt(stats.GetPointDiamondHostIncome(), 10), PointDiamondAgencyShareIncome: strconv.FormatInt(stats.GetPointDiamondAgencyShareIncome(), 10),
		TotalHosts: totalHosts, GiftedHostCount: stats.GetGiftedHostCount(),
	}
}
