export type Message = {
  id: string;
  timestamp: number;
  role: 'user' | 'assistant' | 'tool';
  text?: string;
  model?: string;
  cost?: MessageCost;
  toolCallId?: string;
  toolName?: string;
  toolInput?: Record<string, unknown>;
  output?: string;
  isError?: boolean;
};

export type MessageCost = {
  inputTokens: number;
  outputTokens: number;
  totalUSD: number;
};

export type SessionMeta = {
  id: string;
  title: string;
  model: string;
  cwd: string;
  createdAt: number;
  updatedAt: number;
  messageCount: number;
  cost: MessageCost;
  groupSlug?: string | null;
  context?: string;
  contextId?: string;
};

export type GroupMeta = {
  name: string;
  slug: string;
  description?: string;
  createdAt: number;
  updatedAt: number;
  sessionCount: number;
};

export type ThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';

export type ClientMessage =
  | {
      type: 'chat';
      prompt: string;
      displayText?: string;
      sessionId?: string;
      model?: string;
      cwd?: string;
      cwdRoot?: string;
      groupSlug?: string;
      attachmentIds?: string[];
      thinking?: ThinkingLevel;
      context?: string;
      contextId?: string;
      resumeSummary?: string;
    }
  | {
      type: 'resume';
      sessionId: string;
      cwd?: string;
      cwdRoot?: string;
    }
  | {
      type: 'stop';
    }
  | {
      // Tear down the whole session (kill any in-flight turn + drop the in-memory session), not just
      // the current turn. Frees the session so its transcript can be resumed elsewhere.
      type: 'disconnect';
    }
  | {
      // Sent on (re)connect: re-bind this socket to the session and replay every durable event queued
      // since `cursor` (the last seq the client saw). Powers transparent reconnect without losing
      // background task notifications that landed while disconnected.
      type: 'resume-cursor';
      sessionId: string;
      cursor: number;
    };

export type ServerMessage =
  | {
      type: 'session:init';
      sessionId: string;
      model: string;
      cwd: string;
      context?: string;
      contextId?: string;
    }
  | {
      type: 'assistant:text';
      text: string;
    }
  | {
      type: 'assistant:delta';
      text: string;
    }
  | {
      type: 'tool:start';
      toolCallId: string;
      toolName: string;
      toolInput: Record<string, unknown>;
    }
  | {
      type: 'tool:result';
      toolCallId: string;
      output: string;
      isError: boolean;
    }
  | {
      type: 'result';
      sessionId: string;
      cost: MessageCost;
    }
  | {
      type: 'sync:messages';
      sessionId: string;
      messages: Message[];
      isGenerating: boolean;
      streamingText: string;
    }
  | {
      type: 'error';
      message: string;
      errorCode?: string;
    }
  | {
      type: 'stopped';
    }
  | {
      // Ack for a client 'disconnect': the session was torn down server-side.
      type: 'disconnected';
    }
  | { type: 'task:started'; taskId: string; description: string; taskType?: string }
  | { type: 'task:notification'; taskId: string; status: 'completed' | 'failed' | 'stopped'; summary: string };

export type ChatEvent =
  | { type: 'text'; text: string }
  | { type: 'delta'; text: string }
  | {
      type: 'tool:start';
      toolCallId: string;
      toolName: string;
      toolInput: Record<string, unknown>;
    }
  | {
      type: 'tool:result';
      toolCallId: string;
      output: string;
      isError: boolean;
    }
  | {
      type: 'result';
      cost: MessageCost;
    }
  | { type: 'error'; message: string }
  | { type: 'stopped' }
  // Background-task lifecycle (run_in_background / Monitor), delivered in-stream by the persistent
  // session — including AFTER the turn's `result`, which is the whole point of the persistent worker.
  | { type: 'task:started'; taskId: string; description: string; taskType?: string }
  | { type: 'task:notification'; taskId: string; status: 'completed' | 'failed' | 'stopped'; summary: string };

export type UserSession = {
  sessionId: string;
  email: string;
  userId?: number;
  cwd: string;
  model: string;
  piProcess: any | null;
  ws: any | null;
  lastActivity: number;
  idleTimer: Timer | null;
  streamBuffer: string;
  isGenerating: boolean;
  systemContextSent: boolean;
  messages: Message[];
  meta: SessionMeta;
  _sidecarUnsub?: () => void;
  _claudeKill?: () => void;
};

export type ModelInfo = {
  id: string;
  name: string;
  provider: string;
  contextWindow: number;
  maxTokens: number;
  reasoning?: boolean;
  images?: boolean;
};

// ── Pi-native JSONL types ──────────────────────────────────────────────

export type JnlSessionHeader = {
  type: 'session';
  version: 3;
  id: string;
  timestamp: string;
  cwd: string;
};

export type JnlEntryBase = {
  type: string;
  id: string;
  parentId?: string;
  timestamp: string;
};

export type JnlTextContent = {
  type: 'text';
  text: string;
};

export type JnlToolCall = {
  type: 'tool_use';
  id: string;
  name: string;
  input: Record<string, unknown>;
};

export type JnlUserMessage = JnlEntryBase & {
  type: 'message';
  message: {
    role: 'user';
    content: string | Array<JnlTextContent>;
  };
};

export type JnlAssistantMessage = JnlEntryBase & {
  type: 'message';
  message: {
    role: 'assistant';
    content: Array<JnlTextContent | JnlToolCall>;
  };
};

export type JnlToolResultMessage = JnlEntryBase & {
  type: 'message';
  message: {
    role: 'toolResult';
    toolCallId: string;
    toolName: string;
    content: Array<JnlTextContent>;
    isError?: boolean;
  };
};

export type JnlMessageEntry = JnlUserMessage | JnlAssistantMessage | JnlToolResultMessage;

export type JnlSessionInfoEntry = JnlEntryBase & {
  type: 'session_info';
  name: string;
  officer?: {
    cost: MessageCost;
    model: string;
    groupSlug?: string | null;
    messageCount: number;
    createdAt: number;
    updatedAt: number;
    context?: string;
    contextId?: string;
  };
};

export type JnlEntry = JnlMessageEntry | JnlSessionInfoEntry;

// ── Session Index ──────────────────────────────────────────────────────

export type SessionIndexEntry = {
  file: string;
  title: string;
  model: string;
  cwd: string;
  createdAt: number;
  updatedAt: number;
  messageCount: number;
  cost: MessageCost;
  groupSlug?: string | null;
  context?: string;
  contextId?: string;
};

export type SessionIndex = Record<string, SessionIndexEntry>;
