/**
 * The Socket.IO event contract.
 *
 * Kept in one file so the server and both clients can never drift. The web
 * dashboard and widget import mirrors of these names.
 *
 * Naming: `<domain>:<verb>`. Client-to-server events are imperative
 * ("message:send"); server-to-client events are past tense or noun-ish
 * ("message:new"), which makes the direction obvious at any call site.
 */

/** Namespaces. Customers and agents are fully isolated transports. */
export const NS = {
  customer: '/customer',
  agent: '/agent',
} as const;

/** Room helpers - a conversation room exists in both namespaces. */
export const ROOM = {
  conversation: (id: string) => `conv:${id}`,
  /** Every signed-in agent joins this, for queue and presence fan-out. */
  agentLobby: 'agents:lobby',
  agent: (agentId: string) => `agent:${agentId}`,
} as const;

/* ------------------------------------------------------------------ */
/* Customer -> server                                                  */
/* ------------------------------------------------------------------ */
export const C2S = {
  /** Submit the pre-chat form; opens the conversation. */
  chatStart: 'chat:start',
  /** Resume an existing conversation using a customer token. */
  chatResume: 'chat:resume',
  messageSend: 'message:send',
  typing: 'typing',
  read: 'read',
  /** Ask for everything after a known seq - the reconnect path. */
  historySync: 'history:sync',
  /** Customer asks to end the chat. */
  chatEnd: 'chat:end',
  csatSubmit: 'csat:submit',
} as const;

/* ------------------------------------------------------------------ */
/* Agent -> server                                                     */
/* ------------------------------------------------------------------ */
export const A2S = {
  queueList: 'queue:list',
  queueAccept: 'queue:accept',
  conversationOpen: 'conversation:open',
  conversationClose: 'conversation:close',
  conversationTransfer: 'conversation:transfer',
  conversationPriority: 'conversation:priority',
  messageSend: 'message:send',
  typing: 'typing',
  read: 'read',
  historySync: 'history:sync',
  noteAdd: 'note:add',
  presenceSet: 'presence:set',
} as const;

/* ------------------------------------------------------------------ */
/* Server -> client (both namespaces unless noted)                     */
/* ------------------------------------------------------------------ */
export const S2C = {
  /** Handshake result for the customer widget. */
  chatStarted: 'chat:started',
  chatResumed: 'chat:resumed',

  messageNew: 'message:new',
  /** Batched replay after a reconnect. */
  historyBatch: 'history:batch',

  typing: 'typing',
  read: 'read',

  /** Agent picked the chat up (customer-facing). */
  agentAssigned: 'agent:assigned',
  /** Queue position changed (customer-facing). */
  queuePosition: 'queue:position',

  /** A new chat entered the queue (agent lobby). */
  queueNew: 'queue:new',
  /** A queued chat was taken or otherwise left the queue (agent lobby). */
  queueRemoved: 'queue:removed',
  /** Full queue snapshot (agent lobby). */
  queueSnapshot: 'queue:snapshot',

  conversationUpdated: 'conversation:updated',
  conversationAssigned: 'conversation:assigned',
  conversationTransferred: 'conversation:transferred',
  conversationClosed: 'conversation:closed',

  noteNew: 'note:new',
  csatReceived: 'csat:received',
  presenceUpdate: 'presence:update',

  /** WebRTC screen-share signalling (relayed verbatim). */
  screenOffer: 'screen:offer',
  screenAnswer: 'screen:answer',
  screenIce: 'screen:ice',
  screenStart: 'screen:start',
  screenStop: 'screen:stop',
  screenRequest: 'screen:request',

  error: 'error',
} as const;

/** Screen-share signalling is symmetric, so clients send the same names back. */
export const SCREEN = {
  request: 'screen:request',
  start: 'screen:start',
  offer: 'screen:offer',
  answer: 'screen:answer',
  ice: 'screen:ice',
  stop: 'screen:stop',
} as const;

/** Standard ack envelope for every request/response style event. */
export interface Ack<T = unknown> {
  ok: boolean;
  data?: T;
  error?: { code: string; message: string };
}

export const ackOk = <T>(data: T): Ack<T> => ({ ok: true, data });
export const ackErr = (code: string, message: string): Ack<never> => ({ ok: false, error: { code, message } });
