package message

import (
	"fmt"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/store/model"
)

const (
	ScopeOutboxFanoutMessageMutation = "message_mutation"
	ScopeMessageMutationEventRefType = "app_notification_mutation"

	ScopeMessageMutationUpdate = "update"
	ScopeMessageMutationRecall = "recall"

	scopeMessageMutationPayloadVersion = 1
)

// ScopeMessageMutationFanoutPayload is the durable browser projection for an
// already-committed message edit or recall. It is intentionally separate from
// message.created delivery payloads: replay must never wake Agents or account
// the message as newly unread again.
type ScopeMessageMutationFanoutPayload struct {
	Version            int        `json:"version"`
	Kind               string     `json:"kind"`
	Message            AppMessage `json:"message"`
	UpdateConversation bool       `json:"updateConversation,omitempty"`
}

func MarshalScopeMessageMutationFanoutPayload(payload ScopeMessageMutationFanoutPayload) ([]byte, error) {
	if payload.Version == 0 {
		payload.Version = scopeMessageMutationPayloadVersion
	}
	if payload.Version != scopeMessageMutationPayloadVersion {
		return nil, fmt.Errorf("unsupported scope message mutation payload version %d", payload.Version)
	}
	payload.Kind = strings.TrimSpace(payload.Kind)
	if strings.TrimSpace(payload.Message.ID) == "" || strings.TrimSpace(payload.Message.ChannelID) == "" {
		return nil, fmt.Errorf("scope message mutation payload message and scope are required")
	}
	switch payload.Kind {
	case ScopeMessageMutationUpdate:
		if MessageMetadataIsTombstone(payload.Message.Metadata) {
			return nil, fmt.Errorf("scope message update payload cannot contain a tombstone")
		}
	case ScopeMessageMutationRecall:
		if !MessageMetadataIsTombstone(payload.Message.Metadata) {
			return nil, fmt.Errorf("scope message recall payload requires a tombstone")
		}
	default:
		return nil, fmt.Errorf("scope message mutation payload kind is invalid")
	}
	return model.MarshalJSONObject("scope message mutation fanout payload", payload)
}

func UnmarshalScopeMessageMutationFanoutPayload(raw []byte) (ScopeMessageMutationFanoutPayload, error) {
	if len(raw) == 0 {
		return ScopeMessageMutationFanoutPayload{}, fmt.Errorf("scope message mutation fanout payload is empty")
	}
	var payload ScopeMessageMutationFanoutPayload
	if err := model.UnmarshalJSONObject("scope message mutation fanout payload", raw, &payload); err != nil {
		return ScopeMessageMutationFanoutPayload{}, err
	}
	if payload.Version == 0 {
		payload.Version = scopeMessageMutationPayloadVersion
	}
	if _, err := MarshalScopeMessageMutationFanoutPayload(payload); err != nil {
		return ScopeMessageMutationFanoutPayload{}, err
	}
	return payload, nil
}
