// State service for querying editor state.
//
// Philosophy: Returns raw data only. No rendering, no cell grids.
// Clients (TUI, GUI, Web) decide how to render.

syntax = "proto3";
package reovim.v2;

import "reovim/v2/common.proto";

service StateService {
  // Get current mode.
  rpc GetMode(GetModeRequest) returns (GetModeResponse);

  // Get cursor position.
  rpc GetCursor(GetCursorRequest) returns (GetCursorResponse);

  // Get editor options.
  rpc GetOptions(GetOptionsRequest) returns (GetOptionsResponse);

  // Get window layout tree.
  rpc GetLayout(GetLayoutRequest) returns (GetLayoutResponse);

  // Get visible line range for a window.
  rpc GetVisibleLines(GetVisibleLinesRequest) returns (GetVisibleLinesResponse);

  // Get selection state.
  rpc GetSelection(GetSelectionRequest) returns (GetSelectionResponse);

  // Get rendered screen content via TUI capture relay.
  //
  // Flow: CLI calls this → server sends capture_request notification to TUI →
  //       TUI captures frame → TUI calls SubmitCaptureResponse → this RPC returns.
  //
  // Requires a connected TUI client. Times out if TUI doesn't respond within 5 seconds.
  rpc GetScreenContent(GetScreenContentRequest) returns (GetScreenContentResponse);

  // Submit captured screen content (TUI → Server part of capture relay).
  //
  // Called by TUI in response to a capture_request notification.
  // The request_id must match the one from the notification.
  rpc SubmitCaptureResponse(SubmitCaptureRequest) returns (SubmitCaptureResponseReply);

  // Get register contents.
  //
  // Query one or more vim registers. If no names specified, returns all non-empty registers.
  rpc GetRegisters(GetRegistersRequest) returns (GetRegistersResponse);
}

// Mode

message GetModeRequest {
  // Per-client state (#471): Per-client mode isolation.
  // If client_id > 0, returns the mode for that specific client's mode stack.
  // If client_id == 0 (default), returns the shared session mode (backward compat).
  uint64 client_id = 1;
}

message GetModeResponse {
  string name = 1;        // Internal name (e.g., "normal", "insert")
  string display = 2;     // Display name (e.g., "NORMAL", "INSERT")
  bool is_insert = 3;     // True if mode accepts text input
}

// Cursor

message GetCursorRequest {
  optional uint64 window_id = 1;  // Default: focused window
  // Per-client state (#471): Per-client cursor isolation.
  // If client_id > 0, returns the cursor for that specific client's editing state.
  // If client_id == 0 (default), returns the cursor from the active buffer (backward compat).
  uint64 client_id = 2;
}

message GetCursorResponse {
  uint64 window_id = 1;
  Position position = 2;  // Buffer-relative (0-indexed)
}

// Options

message GetOptionsRequest {
  repeated string names = 1;  // Option names to query (empty = all)
}

message GetOptionsResponse {
  map<string, OptionValue> options = 1;
}

message OptionValue {
  oneof value {
    bool bool_value = 1;
    int64 int_value = 2;
    string string_value = 3;
  }
}

// Layout

message GetLayoutRequest {
  // Phase #471: Per-client window layout.
  // If client_id > 0, returns the layout for that client's editing state.
  // If client_id == 0 (default), returns the shared session layout (backward compat).
  uint64 client_id = 1;
}

message GetLayoutResponse {
  WindowNode root = 1;
  // Optional: None when no windows exist, Some(id) when a window is focused.
  // Phase #479: Use optional to eliminate ID ambiguity (0 vs "no focus").
  optional uint64 focused_window_id = 2;
  // #401: Active tab page ID (absent = no tabs / single tab)
  optional uint64 active_tab_id = 3;
  // #401: Tab page list (empty = no tabs / single tab)
  repeated TabPageInfo tabs = 4;
}

message WindowNode {
  oneof node {
    WindowLeaf leaf = 1;
    WindowSplit split = 2;
  }
}

message WindowLeaf {
  uint64 window_id = 1;
  // Optional: None when window has no buffer, Some(id) when displaying a buffer.
  // Phase #479: Use optional to eliminate ID ambiguity (0 vs "no buffer").
  optional uint64 buffer_id = 2;
  WindowRect rect = 3;
}

message WindowSplit {
  SplitDirection direction = 1;
  repeated WindowNode children = 2;
}

enum SplitDirection {
  SPLIT_DIRECTION_UNSPECIFIED = 0;
  SPLIT_DIRECTION_HORIZONTAL = 1;
  SPLIT_DIRECTION_VERTICAL = 2;
}

// WindowRect is imported from common.proto

// Visible lines

message GetVisibleLinesRequest {
  optional uint64 window_id = 1;  // Default: focused window
  // Phase #471: Per-client visible lines.
  // If client_id > 0, returns visible lines from that client's window layout.
  // If client_id == 0 (default), returns from shared session layout (backward compat).
  uint64 client_id = 2;
}

message GetVisibleLinesResponse {
  uint64 window_id = 1;
  uint64 first_line = 2;    // First visible line (0-indexed)
  uint64 last_line = 3;     // Last visible line (0-indexed)
  uint64 viewport_height = 4;
}

// Selection

message GetSelectionRequest {
  optional uint64 window_id = 1;
  // Phase #471: Per-client selection state.
  // If client_id > 0, returns selection from that client's window layout.
  // If client_id == 0 (default), returns from shared session layout (backward compat).
  uint64 client_id = 2;
}

message GetSelectionResponse {
  bool has_selection = 1;
  optional Selection selection = 2;
  optional string visual_mode = 3;  // "char", "line", "block"
}

// Screen content (TUI migration convenience)

message GetScreenContentRequest {
  // Format: "plain_text", "raw_ansi", "cell_grid"
  string format = 1;
  // Target client ID for capture (required).
  // Routes capture request to the specific TUI client with this ID.
  uint64 client_id = 2;
}

message GetScreenContentResponse {
  uint64 width = 1;
  uint64 height = 2;
  string format = 3;
  string content = 4;  // Formatted screen content
}

// Registers

message GetRegistersRequest {
  repeated string names = 1;  // Register names to query (empty = all non-empty)
  // Per-client state (#515): Per-client register isolation.
  // If client_id > 0, returns the registers for that specific client.
  // If client_id == 0 (default), returns the authenticated client's registers.
  uint64 client_id = 2;
}

message GetRegistersResponse {
  repeated RegisterEntry registers = 1;
}

message RegisterEntry {
  string name = 1;            // Single char register name (e.g., "a", "\"", "0")
  string content_type = 2;    // "text", "macro", or "empty"
  string content = 3;         // Text content or macro notation
  string yank_type = 4;       // For text: "char", "line", "block"; empty for macro
}

// ─────────────────────────────────────────────────────────────────────────────
// Capture relay (TUI → Server)
// ─────────────────────────────────────────────────────────────────────────────

// TUI submits captured screen content in response to capture_request notification.

message SubmitCaptureRequest {
  uint64 request_id = 1;  // Must match request_id from capture_request notification
  uint64 width = 2;       // Frame width
  uint64 height = 3;      // Frame height
  string format = 4;      // Format used for capture
  string content = 5;     // Captured frame content
}

message SubmitCaptureResponseReply {
  bool ok = 1;            // True if the request was matched and delivered
}
