package userapi

import (
	"net/http"
	"strings"

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

type bindInviteReferrerData struct {
	Invite  *inviteBindingData `json:"invite,omitempty"`
	Inviter userProfileData    `json:"inviter"`
}

type currentInviteReferrerData struct {
	Invite  *inviteBindingData `json:"invite,omitempty"`
	Inviter *userProfileData   `json:"inviter,omitempty"`
}

// getMyInviteReferrer 返回当前用户已经绑定的邀请人；未绑定时返回空对象，让 H5 保持搜索入口。
func (h *Handler) getMyInviteReferrer(writer http.ResponseWriter, request *http.Request) {
	if h.userInviteClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	currentUserID := auth.UserIDFromContext(request.Context())

	// 绑定关系以 user-service 的归因表为准，前端不能根据最近一次搜索或本地缓存推断是否已经绑定。
	attributionResp, err := h.userInviteClient.GetInviteAttribution(request.Context(), &userv1.GetInviteAttributionRequest{
		Meta:          httpkit.UserMeta(request, ""),
		InvitedUserId: currentUserID,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	attribution := attributionResp.GetAttribution()
	if attribution == nil || !attribution.GetFound() || strings.TrimSpace(attribution.GetInviteCode()) == "" {
		httpkit.WriteOK(writer, request, currentInviteReferrerData{})
		return
	}

	// 归因表只保存绑定事实和邀请码；展示资料继续走同一个邀请码搜索校验，保证国家、自邀等展示过滤规则和绑定前预览一致。
	searchResp, err := h.userInviteClient.SearchInviteReferrer(request.Context(), &userv1.SearchInviteReferrerRequest{
		Meta:       httpkit.UserMeta(request, ""),
		UserId:     currentUserID,
		InviteCode: attribution.GetInviteCode(),
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	inviter := profileData(searchResp.GetInviter(), 0)
	httpkit.WriteOK(writer, request, currentInviteReferrerData{
		Invite: &inviteBindingData{
			Bound:         true,
			InviteCode:    attribution.GetInviteCode(),
			InviterUserID: userIDString(attribution.GetInviterUserId()),
		},
		Inviter: &inviter,
	})
}

// searchInviteReferrer 只按邀请码暴露当前用户同国家、可绑定的邀请人资料。
func (h *Handler) searchInviteReferrer(writer http.ResponseWriter, request *http.Request) {
	if h.userInviteClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	inviteCode := strings.TrimSpace(request.URL.Query().Get("invite_code"))
	if inviteCode == "" {
		inviteCode = strings.TrimSpace(request.URL.Query().Get("keyword"))
	}
	if inviteCode == "" {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
		return
	}

	resp, err := h.userInviteClient.SearchInviteReferrer(request.Context(), &userv1.SearchInviteReferrerRequest{
		Meta:       httpkit.UserMeta(request, ""),
		UserId:     auth.UserIDFromContext(request.Context()),
		InviteCode: inviteCode,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}

	httpkit.WriteOK(writer, request, map[string]any{"inviter": profileData(resp.GetInviter(), 0)})
}

// bindInviteReferrer 在资料完成后按邀请码绑定邀请归因；跨国家、自邀和重复改绑由 user-service 事务内拒绝。
func (h *Handler) bindInviteReferrer(writer http.ResponseWriter, request *http.Request) {
	if h.userInviteClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}
	var body struct {
		InviteCode string `json:"invite_code"`
	}
	if !httpkit.Decode(writer, request, &body) {
		return
	}
	body.InviteCode = strings.TrimSpace(body.InviteCode)
	if body.InviteCode == "" {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
		return
	}

	resp, err := h.userInviteClient.BindInviteReferrer(request.Context(), &userv1.BindInviteReferrerRequest{
		Meta:       httpkit.UserMeta(request, ""),
		UserId:     auth.UserIDFromContext(request.Context()),
		InviteCode: body.InviteCode,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}

	httpkit.WriteOK(writer, request, bindInviteReferrerData{
		Invite:  inviteBindingDataFromProto(resp.GetInvite()),
		Inviter: profileData(resp.GetInviter(), 0),
	})
}
