package activityapi

import (
	"encoding/json"
	"net/http"
	"strings"

	activityv1 "hyapp.local/api/proto/activity/v1"
	"hyapp/services/gateway-service/internal/auth"
	"hyapp/services/gateway-service/internal/transport/http/httpkit"
)

type taskSectionData struct {
	Section         string         `json:"section"`
	Items           []taskItemData `json:"items"`
	ServerTimeMS    int64          `json:"server_time_ms"`
	NextRefreshAtMS int64          `json:"next_refresh_at_ms"`
}

type taskItemData struct {
	TaskID                string               `json:"task_id"`
	TaskType              string               `json:"task_type"`
	Category              string               `json:"category"`
	MetricType            string               `json:"metric_type"`
	Title                 string               `json:"title"`
	Description           string               `json:"description"`
	AudienceType          string               `json:"audience_type"`
	IconKey               string               `json:"icon_key"`
	IconURL               string               `json:"icon_url"`
	ActionType            string               `json:"action_type"`
	ActionParam           string               `json:"action_param"`
	ActionPayloadJSON     string               `json:"action_payload_json"`
	ActionPayload         map[string]any       `json:"action_payload"`
	DimensionFilterJSON   string               `json:"dimension_filter_json"`
	TargetValue           int64                `json:"target_value"`
	TargetUnit            string               `json:"target_unit"`
	ProgressValue         int64                `json:"progress_value"`
	RewardCoinAmount      int64                `json:"reward_coin_amount"`
	RewardAssetType       string               `json:"reward_asset_type"`
	RewardType            string               `json:"reward_type"`
	RewardResourceID      int64                `json:"reward_resource_id"`
	RewardResourceGroupID int64                `json:"reward_resource_group_id"`
	RewardQuantity        int64                `json:"reward_quantity"`
	RewardDurationMS      int64                `json:"reward_duration_ms"`
	RewardItems           []taskRewardItemData `json:"reward_items"`
	Status                string               `json:"status"`
	Claimable             bool                 `json:"claimable"`
	TaskDay               string               `json:"task_day"`
	ServerTimeMS          int64                `json:"server_time_ms"`
	NextRefreshAtMS       int64                `json:"next_refresh_at_ms"`
	SortOrder             int32                `json:"sort_order"`
	Version               int64                `json:"version"`
}

type taskClaimData struct {
	ClaimID               string               `json:"claim_id"`
	TaskID                string               `json:"task_id"`
	TaskType              string               `json:"task_type"`
	TaskDay               string               `json:"task_day"`
	RewardCoinAmount      int64                `json:"reward_coin_amount"`
	RewardAssetType       string               `json:"reward_asset_type"`
	RewardType            string               `json:"reward_type"`
	RewardResourceID      int64                `json:"reward_resource_id"`
	RewardResourceGroupID int64                `json:"reward_resource_group_id"`
	RewardItems           []taskRewardItemData `json:"reward_items"`
	Status                string               `json:"status"`
	WalletTransactionID   string               `json:"wallet_transaction_id"`
	WalletResourceGrantID string               `json:"wallet_resource_grant_id"`
	GrantedAtMS           int64                `json:"granted_at_ms"`
	Claimed               bool                 `json:"claimed"`
}

type taskRewardItemData struct {
	ItemType          string `json:"item_type"`
	ResourceID        int64  `json:"resource_id"`
	ResourceType      string `json:"resource_type"`
	CoverURL          string `json:"cover_url"`
	Quantity          int64  `json:"quantity"`
	DurationMS        int64  `json:"duration_ms"`
	WalletAssetType   string `json:"wallet_asset_type"`
	WalletAssetAmount int64  `json:"wallet_asset_amount"`
}

type taskClaimRequestBody struct {
	TaskID         string `json:"task_id"`
	TaskIDCamel    string `json:"taskId"`
	TaskType       string `json:"task_type"`
	TaskTypeCamel  string `json:"taskType"`
	TaskDay        string `json:"task_day"`
	TaskDayCamel   string `json:"taskDay"`
	CommandID      string `json:"command_id"`
	CommandIDCamel string `json:"commandId"`
}

func (b taskClaimRequestBody) normalizedTaskID() string {
	if value := strings.TrimSpace(b.TaskID); value != "" {
		return value
	}
	return strings.TrimSpace(b.TaskIDCamel)
}

func (b taskClaimRequestBody) normalizedTaskType() string {
	if value := strings.TrimSpace(b.TaskType); value != "" {
		return value
	}
	return strings.TrimSpace(b.TaskTypeCamel)
}

func (b taskClaimRequestBody) normalizedTaskDay() string {
	if value := strings.TrimSpace(b.TaskDay); value != "" {
		return value
	}
	return strings.TrimSpace(b.TaskDayCamel)
}

func (b taskClaimRequestBody) normalizedCommandID() string {
	if value := strings.TrimSpace(b.CommandID); value != "" {
		return value
	}
	return strings.TrimSpace(b.CommandIDCamel)
}

// listTaskTabs 返回当前用户任务页；进度由 activity-service 事实表决定。
func (h *Handler) listTaskTabs(writer http.ResponseWriter, request *http.Request) {
	if h.taskClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	resp, err := h.taskClient.ListUserTasks(request.Context(), &activityv1.ListUserTasksRequest{
		Meta:   httpkit.ActivityMeta(request),
		UserId: auth.UserIDFromContext(request.Context()),
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	sections := make([]taskSectionData, 0, len(resp.GetSections()))
	for _, section := range resp.GetSections() {
		items := make([]taskItemData, 0, len(section.GetItems()))
		for _, item := range section.GetItems() {
			items = append(items, taskItemFromProto(item))
		}
		sections = append(sections, taskSectionData{
			Section:         section.GetSection(),
			Items:           items,
			ServerTimeMS:    section.GetServerTimeMs(),
			NextRefreshAtMS: section.GetNextRefreshAtMs(),
		})
	}
	httpkit.WriteOK(writer, request, map[string]any{
		"sections":           sections,
		"server_time_ms":     resp.GetServerTimeMs(),
		"next_refresh_at_ms": resp.GetNextRefreshAtMs(),
	})
}

// claimTaskReward 只透传当前用户身份和幂等命令，完成校验及发奖在 activity-service 内完成。
func (h *Handler) claimTaskReward(writer http.ResponseWriter, request *http.Request) {
	if h.taskClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	var body taskClaimRequestBody
	if !httpkit.Decode(writer, request, &body) {
		return
	}
	taskID := body.normalizedTaskID()
	taskType := body.normalizedTaskType()
	taskDay := body.normalizedTaskDay()
	// command_id 是客户端动作的幂等锚点，gateway 只裁剪空白，不替客户端补值。
	commandID := strings.TrimSpace(body.normalizedCommandID())
	if commandID == "" || taskID == "" || taskType == "" || taskDay == "" {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
		return
	}
	resp, err := h.taskClient.ClaimTaskReward(request.Context(), &activityv1.ClaimTaskRewardRequest{
		Meta:      httpkit.ActivityMeta(request),
		UserId:    auth.UserIDFromContext(request.Context()),
		TaskId:    taskID,
		TaskType:  taskType,
		TaskDay:   taskDay,
		CommandId: commandID,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	httpkit.WriteOK(writer, request, taskClaimData{
		ClaimID:               resp.GetClaimId(),
		TaskID:                resp.GetTaskId(),
		TaskType:              resp.GetTaskType(),
		TaskDay:               resp.GetTaskDay(),
		RewardCoinAmount:      resp.GetRewardCoinAmount(),
		RewardAssetType:       resp.GetRewardAssetType(),
		RewardType:            resp.GetRewardType(),
		RewardResourceID:      resp.GetRewardResourceId(),
		RewardResourceGroupID: resp.GetRewardResourceGroupId(),
		RewardItems:           taskRewardItemsFromProto(resp.GetRewardItems()),
		Status:                resp.GetStatus(),
		WalletTransactionID:   resp.GetWalletTransactionId(),
		WalletResourceGrantID: resp.GetWalletResourceGrantId(),
		GrantedAtMS:           resp.GetGrantedAtMs(),
		Claimed:               resp.GetClaimed(),
	})
}

func taskItemFromProto(item *activityv1.TaskItem) taskItemData {
	// gateway 不重新计算任务状态，只把 activity-service 的进度、奖励、图标和跳转元数据转换为 App JSON 合约。
	return taskItemData{
		TaskID:                item.GetTaskId(),
		TaskType:              item.GetTaskType(),
		Category:              item.GetCategory(),
		MetricType:            item.GetMetricType(),
		Title:                 item.GetTitle(),
		Description:           item.GetDescription(),
		AudienceType:          item.GetAudienceType(),
		IconKey:               item.GetIconKey(),
		IconURL:               item.GetIconUrl(),
		ActionType:            item.GetActionType(),
		ActionParam:           item.GetActionParam(),
		ActionPayloadJSON:     item.GetActionPayloadJson(),
		ActionPayload:         taskJSONPayload(item.GetActionPayloadJson()),
		DimensionFilterJSON:   item.GetDimensionFilterJson(),
		TargetValue:           item.GetTargetValue(),
		TargetUnit:            item.GetTargetUnit(),
		ProgressValue:         item.GetProgressValue(),
		RewardCoinAmount:      item.GetRewardCoinAmount(),
		RewardAssetType:       item.GetRewardAssetType(),
		RewardType:            item.GetRewardType(),
		RewardResourceID:      item.GetRewardResourceId(),
		RewardResourceGroupID: item.GetRewardResourceGroupId(),
		RewardQuantity:        item.GetRewardQuantity(),
		RewardDurationMS:      item.GetRewardDurationMs(),
		RewardItems:           taskRewardItemsFromProto(item.GetRewardItems()),
		Status:                item.GetStatus(),
		Claimable:             item.GetClaimable(),
		TaskDay:               item.GetTaskDay(),
		ServerTimeMS:          item.GetServerTimeMs(),
		NextRefreshAtMS:       item.GetNextRefreshAtMs(),
		SortOrder:             item.GetSortOrder(),
		Version:               item.GetVersion(),
	}
}

func taskRewardItemsFromProto(items []*activityv1.TaskRewardItem) []taskRewardItemData {
	result := make([]taskRewardItemData, 0, len(items))
	for _, item := range items {
		if item == nil {
			continue
		}
		result = append(result, taskRewardItemData{
			ItemType:          item.GetItemType(),
			ResourceID:        item.GetResourceId(),
			ResourceType:      item.GetResourceType(),
			CoverURL:          item.GetCoverUrl(),
			Quantity:          item.GetQuantity(),
			DurationMS:        item.GetDurationMs(),
			WalletAssetType:   item.GetWalletAssetType(),
			WalletAssetAmount: item.GetWalletAssetAmount(),
		})
	}
	return result
}

func taskJSONPayload(value string) map[string]any {
	payload := map[string]any{}
	if strings.TrimSpace(value) == "" {
		return payload
	}
	// action_payload_json 是给 App 的辅助结构化字段；解析失败时仍保留原始字符串字段，避免一个配置错误打断整个任务页。
	_ = json.Unmarshal([]byte(value), &payload)
	if payload == nil {
		return map[string]any{}
	}
	return payload
}
