package userapi

import (
	"net/http"
	"strconv"

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

const hostProfileStatusActive = "active"

type hostCenterPolicyData struct {
	PolicyID                 string                      `json:"policy_id"`
	Name                     string                      `json:"name"`
	RegionID                 int64                       `json:"region_id"`
	Status                   string                      `json:"status"`
	SettlementMode           string                      `json:"settlement_mode"`
	SettlementTriggerMode    string                      `json:"settlement_trigger_mode"`
	GiftCoinToDiamondRatio   string                      `json:"gift_coin_to_diamond_ratio"`
	ResidualDiamondToUSDRate string                      `json:"residual_diamond_to_usd_rate"`
	EffectiveFromMS          int64                       `json:"effective_from_ms"`
	EffectiveToMS            int64                       `json:"effective_to_ms"`
	Levels                   []hostCenterPolicyLevelData `json:"levels"`
}

type hostCenterPolicyLevelData struct {
	LevelNo              int32   `json:"level_no"`
	RequiredDiamonds     int64   `json:"required_diamonds"`
	HostSalaryUSDMinor   int64   `json:"host_salary_usd_minor"`
	HostSalaryUSD        float64 `json:"host_salary_usd"`
	HostCoinReward       int64   `json:"host_coin_reward"`
	AgencySalaryUSDMinor int64   `json:"agency_salary_usd_minor"`
	AgencySalaryUSD      float64 `json:"agency_salary_usd"`
	Status               string  `json:"status"`
	SortOrder            int32   `json:"sort_order"`
}

type hostCenterSalaryProgressData struct {
	HostUserID        int64  `json:"host_user_id"`
	CycleKey          string `json:"cycle_key"`
	RegionID          int64  `json:"region_id"`
	AgencyOwnerUserID int64  `json:"agency_owner_user_id"`
	TotalDiamonds     int64  `json:"total_diamonds"`
	GiftDiamondTotal  int64  `json:"gift_diamond_total"`
	UpdatedAtMS       int64  `json:"updated_at_ms"`
}

type hostCenterLevelProgressData struct {
	CurrentLevel            int32 `json:"current_level"`
	CurrentRequiredDiamonds int64 `json:"current_required_diamonds"`
	CurrentValue            int64 `json:"current_value"`
	NextLevel               int32 `json:"next_level"`
	NextRequiredDiamonds    int64 `json:"next_required_diamonds"`
	NeededForNextLevel      int64 `json:"needed_for_next_level"`
}

func (h *Handler) getHostCenterPlatformPolicy(writer http.ResponseWriter, request *http.Request) {
	profile, ok := h.resolveCurrentActiveHostProfile(writer, request)
	if !ok {
		return
	}
	if h.walletClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	// H5 不传 region、policy id 或 trigger；gateway 用当前主播身份区域读取 active 政策，让 automatic/manual 都能展示。
	resp, err := h.walletClient.GetActiveHostSalaryPolicy(request.Context(), &walletv1.GetActiveHostSalaryPolicyRequest{
		RequestId: httpkit.RequestIDFromContext(request.Context()),
		AppCode:   appcode.FromContext(request.Context()),
		RegionId:  profile.GetRegionId(),
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}

	// 等级进度必须按工资周期钻石账户计算，不能使用用户成长等级，否则“距离下一级”会和后台工资政策不一致。
	progressResp, err := h.walletClient.GetHostSalaryProgress(request.Context(), &walletv1.GetHostSalaryProgressRequest{
		RequestId:  httpkit.RequestIDFromContext(request.Context()),
		AppCode:    appcode.FromContext(request.Context()),
		HostUserId: profile.GetUserId(),
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	progress := progressResp.GetProgress()

	httpkit.WriteOK(writer, request, map[string]any{
		"found":          resp.GetFound(),
		"host_region_id": profile.GetRegionId(),
		"policy":         hostCenterPolicyFromProto(resp.GetPolicy()),
		"progress":       hostCenterSalaryProgressFromProto(progress),
		"level_progress": hostCenterLevelProgressFromPolicy(resp.GetPolicy(), progress.GetTotalDiamonds()),
	})
}

func (h *Handler) resolveCurrentActiveHostProfile(writer http.ResponseWriter, request *http.Request) (*userv1.HostProfile, bool) {
	if h.userHostClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return nil, false
	}
	userID := auth.UserIDFromContext(request.Context())
	resp, err := h.userHostClient.GetHostProfile(request.Context(), &userv1.GetHostProfileRequest{
		Meta:   httpkit.UserMeta(request, ""),
		UserId: userID,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return nil, false
	}
	profile := resp.GetHostProfile()
	if profile == nil || profile.GetUserId() != userID || profile.GetStatus() != hostProfileStatusActive || profile.GetRegionId() <= 0 {
		httpkit.WriteError(writer, request, http.StatusForbidden, httpkit.CodePermissionDenied, "permission denied")
		return nil, false
	}
	return profile, true
}

func hostCenterPolicyFromProto(policy *walletv1.HostSalaryPolicy) *hostCenterPolicyData {
	if policy == nil {
		return nil
	}
	levels := make([]hostCenterPolicyLevelData, 0, len(policy.GetLevels()))
	for _, level := range policy.GetLevels() {
		levels = append(levels, hostCenterPolicyLevelFromProto(level))
	}
	return &hostCenterPolicyData{
		PolicyID:                 strconv.FormatUint(policy.GetPolicyId(), 10),
		Name:                     policy.GetName(),
		RegionID:                 policy.GetRegionId(),
		Status:                   policy.GetStatus(),
		SettlementMode:           policy.GetSettlementMode(),
		SettlementTriggerMode:    policy.GetSettlementTriggerMode(),
		GiftCoinToDiamondRatio:   policy.GetGiftCoinToDiamondRatio(),
		ResidualDiamondToUSDRate: policy.GetResidualDiamondToUsdRate(),
		EffectiveFromMS:          policy.GetEffectiveFromMs(),
		EffectiveToMS:            policy.GetEffectiveToMs(),
		Levels:                   levels,
	}
}

func hostCenterPolicyLevelFromProto(level *walletv1.HostSalaryPolicyLevel) hostCenterPolicyLevelData {
	if level == nil {
		return hostCenterPolicyLevelData{}
	}
	return hostCenterPolicyLevelData{
		LevelNo:              level.GetLevelNo(),
		RequiredDiamonds:     level.GetRequiredDiamonds(),
		HostSalaryUSDMinor:   level.GetHostSalaryUsdMinor(),
		HostSalaryUSD:        float64(level.GetHostSalaryUsdMinor()) / 100,
		HostCoinReward:       level.GetHostCoinReward(),
		AgencySalaryUSDMinor: level.GetAgencySalaryUsdMinor(),
		AgencySalaryUSD:      float64(level.GetAgencySalaryUsdMinor()) / 100,
		Status:               level.GetStatus(),
		SortOrder:            level.GetSortOrder(),
	}
}

func hostCenterSalaryProgressFromProto(progress *walletv1.HostSalaryProgress) hostCenterSalaryProgressData {
	if progress == nil {
		return hostCenterSalaryProgressData{}
	}
	return hostCenterSalaryProgressData{
		HostUserID:        progress.GetHostUserId(),
		CycleKey:          progress.GetCycleKey(),
		RegionID:          progress.GetRegionId(),
		AgencyOwnerUserID: progress.GetAgencyOwnerUserId(),
		TotalDiamonds:     progress.GetTotalDiamonds(),
		GiftDiamondTotal:  progress.GetGiftDiamondTotal(),
		UpdatedAtMS:       progress.GetUpdatedAtMs(),
	}
}

func hostCenterLevelProgressFromPolicy(policy *walletv1.HostSalaryPolicy, currentValue int64) *hostCenterLevelProgressData {
	levels := policy.GetLevels()
	if len(levels) == 0 {
		return nil
	}
	var current *walletv1.HostSalaryPolicyLevel
	var next *walletv1.HostSalaryPolicyLevel
	for _, level := range levels {
		if level == nil {
			continue
		}
		required := level.GetRequiredDiamonds()
		if required <= currentValue {
			if current == nil || required > current.GetRequiredDiamonds() {
				current = level
			}
			continue
		}
		if next == nil || required < next.GetRequiredDiamonds() {
			next = level
		}
	}
	result := &hostCenterLevelProgressData{
		CurrentValue: currentValue,
	}
	if current != nil {
		result.CurrentLevel = current.GetLevelNo()
		result.CurrentRequiredDiamonds = current.GetRequiredDiamonds()
	}
	if next != nil {
		result.NextLevel = next.GetLevelNo()
		result.NextRequiredDiamonds = next.GetRequiredDiamonds()
		result.NeededForNextLevel = next.GetRequiredDiamonds() - currentValue
		return result
	}
	result.NextLevel = result.CurrentLevel
	result.NextRequiredDiamonds = result.CurrentRequiredDiamonds
	return result
}
