package userapi

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

	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"
	hostPolicyTypeSalaryDiamond = "SALARY_DIAMOND"
)

type hostCenterPolicyData struct {
	PolicyID                 string                      `json:"policy_id"`
	CycleKey                 string                      `json:"cycle_key"`
	PolicyVersion            uint64                      `json:"policy_version"`
	Name                     string                      `json:"name"`
	PolicyType               string                      `json:"policy_type"`
	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"`
	PointDiamondsPerUSD      int64                       `json:"point_diamonds_per_usd"`
	CoinsPerUSD              int64                       `json:"coins_per_usd"`
	AgencyPointShareBPS      int32                       `json:"agency_point_share_bps"`
	MinimumWithdrawUSDMinor  int64                       `json:"minimum_withdraw_usd_minor"`
	WithdrawFeeBPS           int32                       `json:"withdraw_fee_bps"`
	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
	}

	cycleKey := time.Now().UTC().Format("2006-01")
	// 政策和进度共用同一个 UTC 周期锚点，避免月界瞬间两个调用读取到不同月份。
	resp, err := h.walletClient.GetActiveHostSalaryPolicy(request.Context(), &walletv1.GetActiveHostSalaryPolicyRequest{
		RequestId: httpkit.RequestIDFromContext(request.Context()),
		AppCode:   appcode.FromContext(request.Context()),
		RegionId:  profile.GetRegionId(),
		CycleKey:  cycleKey,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}

	var progressData any
	var levelProgressData any
	policy := resp.GetPolicy()
	if resp.GetFound() && strings.EqualFold(strings.TrimSpace(policy.GetPolicyType()), hostPolicyTypeSalaryDiamond) {
		// 工资周期进度只属于 SALARY_DIAMOND。POINT_DIAMOND 是永久钱包资产，查询或返回工资进度会把旧周期钻石误展示给用户。
		progressResp, err := h.walletClient.GetHostSalaryProgress(request.Context(), &walletv1.GetHostSalaryProgressRequest{
			RequestId:  httpkit.RequestIDFromContext(request.Context()),
			AppCode:    appcode.FromContext(request.Context()),
			HostUserId: profile.GetUserId(),
			CycleKey:   cycleKey,
		})
		if err != nil {
			httpkit.WriteRPCError(writer, request, err)
			return
		}
		progress := progressResp.GetProgress()
		progressData = hostCenterSalaryProgressFromProto(progress)
		levelProgressData = hostCenterLevelProgressFromPolicy(policy, progress.GetTotalDiamonds())
	}

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

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))
	}
	// Host 与 Agency Center 共用该 mapper；政策类型和永久积分参数必须原样透传，
	// 客户端不能通过 levels 是否为空反推类型，也不能自行补不同 App 的默认值。
	return &hostCenterPolicyData{
		PolicyID:                 strconv.FormatUint(policy.GetPolicyId(), 10),
		CycleKey:                 policy.GetCycleKey(),
		PolicyVersion:            policy.GetPolicyVersion(),
		Name:                     policy.GetName(),
		PolicyType:               policy.GetPolicyType(),
		RegionID:                 policy.GetRegionId(),
		Status:                   policy.GetStatus(),
		SettlementMode:           policy.GetSettlementMode(),
		SettlementTriggerMode:    policy.GetSettlementTriggerMode(),
		GiftCoinToDiamondRatio:   policy.GetGiftCoinToDiamondRatio(),
		PointDiamondsPerUSD:      policy.GetPointDiamondsPerUsd(),
		CoinsPerUSD:              policy.GetCoinsPerUsd(),
		AgencyPointShareBPS:      policy.GetAgencyPointShareBps(),
		MinimumWithdrawUSDMinor:  policy.GetMinimumWithdrawUsdMinor(),
		WithdrawFeeBPS:           policy.GetWithdrawFeeBps(),
		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
}
