// diplomail contains FlatBuffers payloads used by the authenticated
// gateway boundary for the in-game diplomatic-mail subsystem. The
// wire shapes here mirror the trusted internal
// `/api/v1/user/games/{game_id}/mail/*` REST surface; gateway derives
// the calling `user_id` from the verified session and forwards it as
// `X-User-Id` to backend.

include "common.fbs";

namespace diplomail;

// MailMessage stores one inbox / sent-list / message-detail row. The
// fields mirror `UserMailMessageDetail` in `backend/openapi.yaml`
// with the following encoding rules:
//
//   - `*_user_id` fields are RFC 4122 string UUIDs ("" means absent
//     for nullable fields such as `sender_user_id`).
//   - `*_at_ms` fields carry Unix milliseconds; `0` means the
//     timestamp is absent (e.g. an unread message has
//     `read_at_ms == 0`).
//   - `translated_*`, `translation_lang`, and `translator` are set
//     when the backend served a cached rendering into the caller's
//     preferred language; empty otherwise.
//   - `sender_race_name` is the snapshot of the sender's race name
//     in this game at send time. Present for `sender_kind="player"`
//     messages when the sender had an active membership; absent for
//     admin and system messages. The in-game UI keys per-race
//     threading on this field.
table MailMessage {
  message_id:string;
  game_id:string;
  game_name:string;
  kind:string;
  sender_kind:string;
  sender_user_id:string;
  sender_username:string;
  sender_race_name:string;
  subject:string;
  body:string;
  body_lang:string;
  broadcast_scope:string;
  created_at_ms:int64;
  recipient_user_id:string;
  recipient_user_name:string;
  recipient_race_name:string;
  read_at_ms:int64;
  deleted_at_ms:int64;
  translated_subject:string;
  translated_body:string;
  translation_lang:string;
  translator:string;
}

// MailRecipientState mirrors the `UserMailRecipientState` payload
// returned from mark-read and soft-delete endpoints. Same timestamp
// conventions as `MailMessage`.
table MailRecipientState {
  message_id:string;
  read_at_ms:int64;
  deleted_at_ms:int64;
}

// MailBroadcastReceipt mirrors `UserMailBroadcastReceipt`. Returned
// from broadcast sends (paid-tier and admin); `recipient_count` is
// the number of recipient rows the server materialised.
table MailBroadcastReceipt {
  message_id:string;
  game_id:string;
  game_name:string;
  kind:string;
  sender_kind:string;
  subject:string;
  body:string;
  body_lang:string;
  broadcast_scope:string;
  created_at_ms:int64;
  recipient_count:int32;
}

// InboxRequest stores the read-side request for the caller's inbox
// in `game_id`. Backend filters to messages with `available_at` set
// (translation completed when the recipient's preferred language
// differs from the body language).
table InboxRequest {
  game_id:common.UUID (required);
}

// InboxResponse stores the resulting inbox list, newest first.
// `items` is empty when the caller has no available messages in
// this game.
table InboxResponse {
  items:[MailMessage];
}

// SentRequest stores the read-side request for the caller's sent
// personal messages in `game_id`. Admin / system rows are not
// included.
table SentRequest {
  game_id:common.UUID (required);
}

// SentResponse stores the caller's outgoing personal-message list.
// Each `MailMessage` carries the original recipient snapshot.
table SentResponse {
  items:[MailMessage];
}

// MessageGetRequest stores the read-side request for a single
// message detail. The caller must be a recipient of the message.
table MessageGetRequest {
  game_id:common.UUID (required);
  message_id:common.UUID (required);
}

// MessageGetResponse stores the fully decorated message detail
// including any cached translation into the caller's preferred
// language.
table MessageGetResponse {
  message:MailMessage;
}

// SendRequest stores the write-side request for a single-recipient
// personal send. Exactly one of `recipient_user_id` /
// `recipient_race_name` must be supplied; the empty string means
// "use the other field".
table SendRequest {
  game_id:common.UUID (required);
  recipient_user_id:string;
  recipient_race_name:string;
  subject:string;
  body:string;
}

// SendResponse echoes the freshly inserted message detail.
table SendResponse {
  message:MailMessage;
}

// BroadcastRequest stores the paid-tier player broadcast. The
// recipient set is always "every other active member of the game".
table BroadcastRequest {
  game_id:common.UUID (required);
  subject:string;
  body:string;
}

// BroadcastResponse stores the receipt returned by the server.
table BroadcastResponse {
  receipt:MailBroadcastReceipt;
}

// AdminRequest stores the owner-only admin send. `target="user"`
// requires exactly one of `recipient_user_id` / `recipient_race_name`;
// `target="all"` accepts the optional `recipients` scope (default
// `active`).
table AdminRequest {
  game_id:common.UUID (required);
  target:string;
  recipient_user_id:string;
  recipient_race_name:string;
  recipients:string;
  subject:string;
  body:string;
}

// AdminResponse carries the result of an admin send. When the
// request had `target="user"`, `message` is set; when `target="all"`,
// `receipt` is set. Callers branch on which field is present.
table AdminResponse {
  message:MailMessage;
  receipt:MailBroadcastReceipt;
}

// ReadRequest stores the mark-read intent for a single message. The
// caller must be a recipient. Idempotent.
table ReadRequest {
  game_id:common.UUID (required);
  message_id:common.UUID (required);
}

// ReadResponse echoes the recipient state after the operation.
table ReadResponse {
  state:MailRecipientState;
}

// DeleteRequest stores the soft-delete intent for a single message.
// The message must already be marked read (HTTP 409 otherwise).
table DeleteRequest {
  game_id:common.UUID (required);
  message_id:common.UUID (required);
}

// DeleteResponse echoes the recipient state after the operation.
table DeleteResponse {
  state:MailRecipientState;
}
