package dto

// Chat transcript upload.
//
// Agora RTM stores nothing, so the apps buffer the conversation and post it
// when the chat ends — and again on reconnect if that failed. Posting the same
// batch twice is free and safe by design, which is what makes blind retry the
// correct client behaviour.
//
// Both parties upload the same conversation. Whichever gets there first
// defines the record; the other's copy comes back as duplicates. If one phone
// dies, the transcript survives on the other.

type SyncMessagesRequest struct {
	ConsultationID uint `json:"consultation_id" binding:"required"`

	Messages []SyncMessageItem `json:"messages" binding:"required,min=1,max=500,dive"`

	// Set on the final batch. Advisory only — there is no "transcript
	// complete" state, because a later batch from the other party is normal.
	IsFinal bool `json:"is_final"`
}

type SyncMessageItem struct {
	// Generated ONCE by the sending device and carried inside the RTM
	// payload, so the receiving device echoes back the same id.
	//
	// This is the dedupe key. If each app invents its own id on receipt,
	// every message is stored twice and the server cannot tell.
	ClientMessageID string `json:"client_message_id" binding:"required,max=64"`

	// USER, ASTROLOGER or SYSTEM. Who wrote it — not who is uploading it.
	SenderType string `json:"sender_type" binding:"required"`

	// TEXT (default). Anything else is rejected in v1.
	MessageType string `json:"message_type"`

	Body string `json:"body"`

	// The sending device's clock: "2006-01-02 15:04:05.000", the same without
	// milliseconds, or RFC3339.
	SentAt string `json:"sent_at"`

	// The sender's own counter within the session. Breaks ties when two
	// devices' clocks disagree.
	Sequence int `json:"sequence"`
}

type RejectedMessage struct {
	ClientMessageID string `json:"client_message_id"`
	Reason          string `json:"reason"`
}

type SyncMessagesResponse struct {
	ConsultationID uint `json:"consultation_id"`

	Received int `json:"received"`
	Stored   int `json:"stored"`

	// Not a problem. A high duplicate count is the healthy, expected result
	// of the other party having uploaded first.
	Duplicate int `json:"duplicate"`

	Truncated int `json:"truncated"`

	Rejected []RejectedMessage `json:"rejected,omitempty"`

	// Everything on this session from both uploads, so the app can compare
	// against its own buffer and decide whether to re-post.
	TotalStored int64 `json:"total_stored"`

	// After this the session stops accepting uploads. Empty while the session
	// is still running.
	WindowClosesAt string `json:"window_closes_at,omitempty"`
}

type ChatMessageItem struct {
	ID              uint   `json:"id"`
	ClientMessageID string `json:"client_message_id"`
	SenderType      string `json:"sender_type"`
	SenderID        uint   `json:"sender_id"`
	MessageType     string `json:"message_type"`
	Body            string `json:"body"`
	SentAt          string `json:"sent_at"`
}

type ConsultationMessagesResponse struct {
	ConsultationID uint   `json:"consultation_id"`
	ConsultationNo string `json:"consultation_no"`

	Items []ChatMessageItem `json:"items"`

	Page       int   `json:"page"`
	Limit      int   `json:"limit"`
	Total      int64 `json:"total"`
	TotalPages int   `json:"total_pages"`
}
