package appapi

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

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

// handlePushToken 分发 push token 绑定和失效。
// 设备 token 属于 user-service 主数据扩展，gateway 只做鉴权、字段透传和 HTTP method 约束。
func (h *Handler) handlePushToken(writer http.ResponseWriter, request *http.Request) {
	switch request.Method {
	case http.MethodPost:
		h.bindPushToken(writer, request)
	case http.MethodDelete:
		h.deletePushToken(writer, request)
	default:
		httpkit.WriteError(writer, request, http.StatusMethodNotAllowed, httpkit.CodeInvalidArgument, "invalid argument")
	}
}

func (h *Handler) bindPushToken(writer http.ResponseWriter, request *http.Request) {
	if h.userDeviceClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	var body struct {
		DeviceID   string `json:"device_id"`
		PushToken  string `json:"push_token"`
		Provider   string `json:"provider"`
		Platform   string `json:"platform"`
		AppVersion string `json:"app_version"`
		Language   string `json:"language"`
		Timezone   string `json:"timezone"`
	}
	if !httpkit.Decode(writer, request, &body) {
		return
	}
	body.DeviceID = pushDeviceID(request, body.DeviceID)
	body.Platform = pushPlatform(request, body.Platform)

	resp, err := h.userDeviceClient.BindPushToken(request.Context(), &userv1.BindPushTokenRequest{
		Meta:       httpkit.UserMeta(request, body.DeviceID),
		UserId:     auth.UserIDFromContext(request.Context()),
		DeviceId:   body.DeviceID,
		PushToken:  strings.TrimSpace(body.PushToken),
		Provider:   body.Provider,
		Platform:   body.Platform,
		AppVersion: body.AppVersion,
		Language:   body.Language,
		Timezone:   body.Timezone,
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	httpkit.WriteOK(writer, request, bindPushTokenDataFromProto(resp))
}

func (h *Handler) deletePushToken(writer http.ResponseWriter, request *http.Request) {
	if h.userDeviceClient == nil {
		httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
		return
	}

	var body struct {
		DeviceID  string `json:"device_id"`
		PushToken string `json:"push_token"`
	}
	if !httpkit.Decode(writer, request, &body) {
		return
	}
	body.DeviceID = pushDeviceID(request, body.DeviceID)

	resp, err := h.userDeviceClient.DeletePushToken(request.Context(), &userv1.DeletePushTokenRequest{
		Meta:      httpkit.UserMeta(request, body.DeviceID),
		UserId:    auth.UserIDFromContext(request.Context()),
		DeviceId:  body.DeviceID,
		PushToken: strings.TrimSpace(body.PushToken),
	})
	if err != nil {
		httpkit.WriteRPCError(writer, request, err)
		return
	}
	httpkit.WriteOK(writer, request, deletePushTokenDataFromProto(resp))
}

// bindPushTokenData/deletePushTokenData 固定外部 JSON 字段，避免 proto3 false 被省略。
type bindPushTokenData struct {
	Bound       bool  `json:"bound"`
	UpdatedAtMS int64 `json:"updated_at_ms"`
}

type deletePushTokenData struct {
	Deleted     bool  `json:"deleted"`
	UpdatedAtMS int64 `json:"updated_at_ms"`
}

func bindPushTokenDataFromProto(resp *userv1.BindPushTokenResponse) bindPushTokenData {
	if resp == nil {
		return bindPushTokenData{}
	}

	return bindPushTokenData{Bound: resp.GetBound(), UpdatedAtMS: resp.GetUpdatedAtMs()}
}

func deletePushTokenDataFromProto(resp *userv1.DeletePushTokenResponse) deletePushTokenData {
	if resp == nil {
		return deletePushTokenData{}
	}

	return deletePushTokenData{Deleted: resp.GetDeleted(), UpdatedAtMS: resp.GetUpdatedAtMs()}
}

func pushDeviceID(request *http.Request, bodyValue string) string {
	if value := strings.TrimSpace(bodyValue); value != "" {
		return value
	}
	return httpkit.FirstHeader(request, "X-Device-ID", "X-HY-Device-ID")
}

func pushPlatform(request *http.Request, bodyValue string) string {
	if value := strings.TrimSpace(bodyValue); value != "" {
		return value
	}
	return httpkit.FirstHeader(request, "X-App-Platform", "X-Platform")
}
