package http

import (
	"hyapp/services/gateway-service/internal/transport/http/httpkit"
	"net/http"
	"strings"

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

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"`
	TargetValue      int64  `json:"target_value"`
	TargetUnit       string `json:"target_unit"`
	ProgressValue    int64  `json:"progress_value"`
	RewardCoinAmount int64  `json:"reward_coin_amount"`
	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"`
	Status              string `json:"status"`
	WalletTransactionID string `json:"wallet_transaction_id"`
	GrantedAtMS         int64  `json:"granted_at_ms"`
	Claimed             bool   `json:"claimed"`
}

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:   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 !decode(writer, request, &body) {
		return
	}
	taskID := body.normalizedTaskID()
	taskType := body.normalizedTaskType()
	taskDay := body.normalizedTaskDay()
	commandID := normalizeCommandID(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:      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(),
		Status:              resp.GetStatus(),
		WalletTransactionID: resp.GetWalletTransactionId(),
		GrantedAtMS:         resp.GetGrantedAtMs(),
		Claimed:             resp.GetClaimed(),
	})
}

func taskItemFromProto(item *activityv1.TaskItem) taskItemData {
	return taskItemData{
		TaskID:           item.GetTaskId(),
		TaskType:         item.GetTaskType(),
		Category:         item.GetCategory(),
		MetricType:       item.GetMetricType(),
		Title:            item.GetTitle(),
		Description:      item.GetDescription(),
		TargetValue:      item.GetTargetValue(),
		TargetUnit:       item.GetTargetUnit(),
		ProgressValue:    item.GetProgressValue(),
		RewardCoinAmount: item.GetRewardCoinAmount(),
		Status:           item.GetStatus(),
		Claimable:        item.GetClaimable(),
		TaskDay:          item.GetTaskDay(),
		ServerTimeMS:     item.GetServerTimeMs(),
		NextRefreshAtMS:  item.GetNextRefreshAtMs(),
		SortOrder:        item.GetSortOrder(),
		Version:          item.GetVersion(),
	}
}
