/**
 * Annotations Channel State Types — Per-session inline file-annotation state
 * exposed on the `ahp-session:/<uuid>/annotations` channel.
 *
 * Each session owns at most one annotations channel. The channel URI is
 * derived from the session URI by appending `/annotations` and is also
 * surfaced explicitly on {@link AnnotationsSummary.resource} for badge UI.
 *
 * @module channels-annotations/state
 */

import type { URI, StringOrMarkdown, TextRange } from '../common/state.js';

// ─── Annotations Summary ─────────────────────────────────────────────────────

/**
 * Lightweight per-session summary of the annotations channel, surfaced on
 * {@link SessionSummary.annotations} so badge UI can render annotation /
 * entry counts without subscribing to the channel itself.
 *
 * @category Annotations
 */
export interface AnnotationsSummary {
  /**
   * The subscribable annotations channel URI for the owning session
   * (typically `ahp-session:/<uuid>/annotations`). Surfaced explicitly even
   * though it is derivable from the session URI so badge UI does not need
   * to know the derivation rule.
   */
  resource: URI;
  /** Total number of {@link Annotation} entries in the channel. */
  annotationCount: number;
  /** Total number of {@link AnnotationEntry} entries across every annotation. */
  entryCount: number;
}

// ─── Annotations State ───────────────────────────────────────────────────────

/**
 * Full state for a session's annotations channel, returned when a client
 * subscribes to an `ahp-session:/<uuid>/annotations` URI.
 *
 * @category Annotations
 */
export interface AnnotationsState {
  /** Annotations in this channel, keyed by {@link Annotation.id}. */
  annotations: Annotation[];
}

// ─── Annotation ──────────────────────────────────────────────────────────────

/**
 * A conversation anchored to a specific file produced by a specific turn,
 * optionally narrowed to a range within that file.
 *
 * {@link turnId} anchors the annotation to the file versions that turn
 * produced, so a later turn that rewrites the same file does not silently
 * invalidate the annotation's anchor — clients can resolve {@link resource}
 * and {@link range} against the turn's changeset. When {@link range} is
 * omitted the annotation is anchored to the entire file.
 *
 * Every annotation MUST contain at least one {@link AnnotationEntry}. An
 * {@link AnnotationsSetAction} that creates an annotation therefore carries
 * its mandatory first entry, and removing the last remaining entry collapses
 * the annotation via {@link AnnotationsRemovedAction} rather than leaving an
 * empty annotation behind.
 *
 * @category Annotations
 */
export interface Annotation {
  /**
   * Stable identifier within the annotations channel. Assigned by the client
   * that dispatches the creating {@link AnnotationsSetAction}.
   */
  id: string;
  /**
   * Turn that produced the file versions this annotation is anchored to.
   * Matches a {@link Turn.id} on the owning session.
   */
  turnId: string;
  /** The file the annotation is anchored to. */
  resource: URI;
  /**
   * Range within {@link resource} the annotation is anchored to. When
   * omitted the annotation is anchored to the entire file.
   */
  range?: TextRange;
  /**
   * Whether the annotation has been resolved. Newly created annotations are
   * always unresolved (`false`); a client marks an annotation resolved (or
   * re-opens it) by dispatching an {@link AnnotationsUpdatedAction} carrying
   * the updated flag (or an {@link AnnotationsSetAction} when replacing the
   * whole annotation).
   */
  resolved: boolean;
  /**
   * Entries in this annotation, in dispatch order (oldest first). MUST
   * contain at least one entry.
   */
  entries: AnnotationEntry[];
  /**
   * Producer-defined opaque metadata, surfaced to tooling but not
   * interpreted by the protocol.
   */
  _meta?: Record<string, unknown>;
}

// ─── Annotation Entry ────────────────────────────────────────────────────────

/**
 * A single entry within an {@link Annotation}.
 *
 * @category Annotations
 */
export interface AnnotationEntry {
  /**
   * Stable identifier within the enclosing annotation. Assigned by the client
   * that dispatches the {@link AnnotationsEntrySetAction} (or the enclosing
   * {@link AnnotationsSetAction}) introducing the entry.
   */
  id: string;
  /**
   * Entry body. A bare `string` is rendered as plain text; pass
   * `{ markdown: "…" }` to opt into Markdown rendering. See
   * {@link StringOrMarkdown}.
   */
  text: StringOrMarkdown;
  /**
   * Producer-defined opaque metadata, surfaced to tooling but not
   * interpreted by the protocol.
   */
  _meta?: Record<string, unknown>;
}
