package roomapi

import (
	"net/http"
	"strings"

	roomv1 "hyapp.local/api/proto/room/v1"
	"hyapp/pkg/giftlimits"
	"hyapp/pkg/roomid"
	"hyapp/services/gateway-service/internal/transport/http/httpkit"
)

type roomDecorationData struct {
	ResourceID    int64     `json:"resource_id"`
	ResourceCode  string    `json:"resource_code"`
	ResourceType  string    `json:"resource_type"`
	Name          string    `json:"name"`
	AssetURL      string    `json:"asset_url"`
	PreviewURL    string    `json:"preview_url,omitempty"`
	AnimationURL  string    `json:"animation_url,omitempty"`
	Format        string    `json:"format,omitempty"`
	MetadataJSON  string    `json:"metadata_json,omitempty"`
	EntitlementID string    `json:"entitlement_id"`
	TextColors    []string  `json:"text_colors,omitempty"`
	Stops         []float64 `json:"stops,omitempty"`
	AngleDegrees  float64   `json:"angle_degrees,omitempty"`
	ExpiresAtMS   int64     `json:"expires_at_ms,omitempty"`
}

type applyRoomDecorationData struct {
	Result         roomCommandResultData `json:"result"`
	Room           roomInitialData       `json:"room"`
	DecorationType string                `json:"decoration_type"`
	Resource       *roomDecorationData   `json:"resource,omitempty"`
	ServerTimeMS   int64                 `json:"server_time_ms"`
}

type saveRoomBorderData struct {
	Result        roomCommandResultData `json:"result"`
	Room          roomInitialData       `json:"room"`
	RoomBorderURL string                `json:"room_border_url"`
	Resource      *roomDecorationData   `json:"resource,omitempty"`
	ServerTimeMS  int64                 `json:"server_time_ms"`
}

type sendRoomImageData struct {
	Result       roomCommandResultData `json:"result"`
	Accepted     bool                  `json:"accepted"`
	MessageID    string                `json:"message_id"`
	RoomID       string                `json:"room_id"`
	SenderUserID string                `json:"sender_user_id"`
	ServerTimeMS int64                 `json:"server_time_ms"`
	Image        *roomMediaData        `json:"image,omitempty"`
}

func (h *Handler) applyRoomDecoration(writer http.ResponseWriter, request *http.Request) {
	if h.roomVIPClient == nil {
		httpkit.WriteError(writer, request, http.StatusServiceUnavailable, httpkit.CodeUpstreamError, "room vip feature is unavailable")
		return
	}
	roomID := strings.TrimSpace(request.PathValue("room_id"))
	var body struct {
		CommandID      string        `json:"command_id"`
		DecorationType string        `json:"decoration_type"`
		ResourceID     flexibleInt64 `json:"resource_id"`
		EntitlementID  string        `json:"entitlement_id"`
	}
	if !httpkit.Decode(writer, request, &body) {
		return
	}
	body.CommandID = strings.TrimSpace(body.CommandID)
	body.DecorationType = strings.ToLower(strings.TrimSpace(body.DecorationType))
	body.EntitlementID = strings.TrimSpace(body.EntitlementID)
	if !roomid.ValidStringID(roomID) || !giftlimits.ValidCommandID(body.CommandID) || int64(body.ResourceID) <= 0 {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
		return
	}
	resp, err := h.roomVIPClient.ApplyRoomDecoration(request.Context(), &roomv1.ApplyRoomDecorationRequest{
		Meta: httpkit.RoomMeta(request, roomID, body.CommandID), DecorationType: body.DecorationType,
		ResourceId: int64(body.ResourceID), EntitlementId: body.EntitlementID,
	})
	httpkit.Write(writer, request, applyRoomDecorationDataFromProto(resp), err)
}

// saveRoomBorder 是 Flutter 保存房间边框的专用入口。
// URL 必须来自 wallet 的 room_border 资源目录，客户端只提交资源身份，不能用任意 URL 绕过 entitlement/VIP 校验。
func (h *Handler) saveRoomBorder(writer http.ResponseWriter, request *http.Request) {
	if h.roomVIPClient == nil {
		httpkit.WriteError(writer, request, http.StatusServiceUnavailable, httpkit.CodeUpstreamError, "room vip feature is unavailable")
		return
	}
	roomID := strings.TrimSpace(request.PathValue("room_id"))
	var body struct {
		CommandID     string        `json:"command_id"`
		ResourceID    flexibleInt64 `json:"resource_id"`
		EntitlementID string        `json:"entitlement_id"`
	}
	if !httpkit.Decode(writer, request, &body) {
		return
	}
	body.CommandID = strings.TrimSpace(body.CommandID)
	body.EntitlementID = strings.TrimSpace(body.EntitlementID)
	if !roomid.ValidStringID(roomID) || !giftlimits.ValidCommandID(body.CommandID) || int64(body.ResourceID) <= 0 {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
		return
	}
	resp, err := h.roomVIPClient.ApplyRoomDecoration(request.Context(), &roomv1.ApplyRoomDecorationRequest{
		Meta:           httpkit.RoomMeta(request, roomID, body.CommandID),
		DecorationType: "room_border",
		ResourceId:     int64(body.ResourceID),
		EntitlementId:  body.EntitlementID,
	})
	httpkit.Write(writer, request, saveRoomBorderDataFromProto(resp), err)
}

func (h *Handler) sendRoomImage(writer http.ResponseWriter, request *http.Request) {
	if h.roomVIPClient == nil || h.objectURLVerifier == nil {
		httpkit.WriteError(writer, request, http.StatusServiceUnavailable, httpkit.CodeUpstreamError, "room image message is unavailable")
		return
	}
	roomID := strings.TrimSpace(request.PathValue("room_id"))
	var body struct {
		CommandID string        `json:"command_id"`
		Image     roomMediaData `json:"image"`
	}
	if !httpkit.Decode(writer, request, &body) {
		return
	}
	body.CommandID = strings.TrimSpace(body.CommandID)
	if !roomid.ValidStringID(roomID) || !giftlimits.ValidCommandID(body.CommandID) ||
		!h.objectURLVerifier.OwnsObjectURL(body.Image.URL, body.Image.ObjectKey) {
		httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid room image")
		return
	}
	resp, err := h.roomVIPClient.SendRoomImage(request.Context(), &roomv1.SendRoomImageRequest{
		Meta: httpkit.RoomMeta(request, roomID, body.CommandID), Image: body.Image.proto(),
	})
	httpkit.Write(writer, request, sendRoomImageDataFromProto(resp), err)
}

func applyRoomDecorationDataFromProto(resp *roomv1.ApplyRoomDecorationResponse) applyRoomDecorationData {
	if resp == nil {
		return applyRoomDecorationData{}
	}
	return applyRoomDecorationData{
		Result: commandResultDataFromProto(resp.GetResult()), Room: roomInitialRoomDataFromSnapshot(resp.GetRoom(), resp.GetRoom().GetRoomId()),
		DecorationType: resp.GetDecorationType(), Resource: roomDecorationDataFromProto(resp.GetResource()), ServerTimeMS: resp.GetServerTimeMs(),
	}
}

func saveRoomBorderDataFromProto(resp *roomv1.ApplyRoomDecorationResponse) saveRoomBorderData {
	if resp == nil {
		return saveRoomBorderData{}
	}
	room := roomInitialRoomDataFromSnapshot(resp.GetRoom(), resp.GetRoom().GetRoomId())
	return saveRoomBorderData{
		Result:        commandResultDataFromProto(resp.GetResult()),
		Room:          room,
		RoomBorderURL: roomBorderURL(room.RoomBorderURL, resp.GetResource()),
		Resource:      roomDecorationDataFromProto(resp.GetResource()),
		ServerTimeMS:  resp.GetServerTimeMs(),
	}
}

func sendRoomImageDataFromProto(resp *roomv1.SendRoomImageResponse) sendRoomImageData {
	if resp == nil {
		return sendRoomImageData{}
	}
	return sendRoomImageData{
		Result: commandResultDataFromProto(resp.GetResult()), Accepted: resp.GetAccepted(), MessageID: resp.GetMessageId(),
		RoomID: resp.GetRoomId(), SenderUserID: formatOptionalUserID(resp.GetSenderUserId()),
		ServerTimeMS: resp.GetServerTimeMs(), Image: roomMediaDataFromProto(resp.GetImage()),
	}
}

func roomDecorationDataFromProto(resource *roomv1.RoomDecorationResource) *roomDecorationData {
	if resource == nil || resource.GetResourceId() <= 0 {
		return nil
	}
	return &roomDecorationData{
		ResourceID: resource.GetResourceId(), ResourceCode: resource.GetResourceCode(), ResourceType: resource.GetResourceType(),
		Name: resource.GetName(), AssetURL: resource.GetAssetUrl(), PreviewURL: resource.GetPreviewUrl(), AnimationURL: resource.GetAnimationUrl(),
		Format: resource.GetFormat(), MetadataJSON: resource.GetMetadataJson(), EntitlementID: resource.GetEntitlementId(),
		TextColors: append([]string(nil), resource.GetTextColors()...), Stops: append([]float64(nil), resource.GetStops()...),
		AngleDegrees: resource.GetAngleDegrees(), ExpiresAtMS: resource.GetExpiresAtMs(),
	}
}
