/** Session runtime for token/NPC path playback and presentation visibility. */

export type TokenPathTargetKind = 'token' | 'npcToken';

export type TokenPathTargetRef = {
  kind: TokenPathTargetKind;
  placementId: string;
};

export function tokenPathKey(kind: TokenPathTargetKind, placementId: string): string {
  return `${kind}:${placementId}`;
}

export function parseTokenPathKey(key: string): TokenPathTargetRef | null {
  const i = key.indexOf(':');
  if (i <= 0) return null;
  const kind = key.slice(0, i);
  const placementId = key.slice(i + 1);
  if ((kind !== 'token' && kind !== 'npcToken') || !placementId) return null;
  return { kind, placementId };
}

/**
 * delay — waiting startMode delayed.
 * moving — animating along path (or rejoining after drag).
 * done — once finished at end.
 * stopped — user stopped; drag allowed; can resume.
 */
export type TokenPathPlaybackPhase = 'delay' | 'moving' | 'done' | 'stopped';

export type TokenPathPlaybackEntry = {
  kind: TokenPathTargetKind;
  placementId: string;
  phase: TokenPathPlaybackPhase;
  /** Wall-clock ms when current moving/delay segment started (main Date.now). */
  segmentStartedAtMs: number;
  /** Path distance at segment start (for moving). */
  baseDist: number;
  direction: 1 | -1;
  /** If set while moving: first travel to this dist (rejoin), then clear. */
  rejoinDist: number | null;
  /** Snapshot of durationSec from path at start. */
  durationSec: number;
  /** Snapshot of total polyline length at start. */
  pathLength: number;
};

export type TokenPathSessionState = {
  revision: number;
  /** Keys visible on presentation («Показать путь»). */
  presentationVisible: Record<string, true>;
  playback: Record<string, TokenPathPlaybackEntry>;
  /** Monotonic clock for renderers (updated on dispatch / heartbeats). */
  serverNowMs: number;
};

export type TokenPathSessionEvent =
  | { kind: 'clear' }
  | { kind: 'showPresentation'; target: TokenPathTargetRef }
  | { kind: 'hidePresentation'; target: TokenPathTargetRef }
  | { kind: 'stop'; target: TokenPathTargetRef; atDist?: number }
  | { kind: 'resume'; target: TokenPathTargetRef; nx: number; ny: number; fromDist: number }
  | { kind: 'resetToStart'; target: TokenPathTargetRef }
  | {
      kind: 'seedPlayback';
      entry: Omit<TokenPathPlaybackEntry, 'segmentStartedAtMs'> & { segmentStartedAtMs?: number };
    }
  | { kind: 'markDone'; target: TokenPathTargetRef };

export function emptyTokenPathSessionState(revision = 1): TokenPathSessionState {
  return {
    revision,
    presentationVisible: {},
    playback: {},
    serverNowMs: Date.now(),
  };
}
