/** DTOs for the internal bridge API consumed by agent-comms host daemons. */

export interface BridgeMessageDto {
  room_id: string;
  /** Agent slug (localpart suffix), e.g. "pi0-web1". */
  agent: string;
  body: string;
  thread_root?: string;
  msgtype?: string;
  /** Optional protocol payload merged into content (e.g. org.uscllc.agent). */
  extra_content?: Record<string, unknown>;
}

export interface BridgeTypingDto {
  room_id: string;
  agent: string;
  typing: boolean;
}

const AGENT_SLUG_RE = /^[a-z0-9][a-z0-9_.-]*$/;

const assertAgentSlug = (agent: unknown): void => {
  if (typeof agent !== 'string' || !AGENT_SLUG_RE.test(agent.toLowerCase())) {
    throw new Error('agent must match [a-z0-9][a-z0-9_.-]*');
  }
};

export function validateBridgeMessage(input: unknown): asserts input is BridgeMessageDto {
  const o = input as Partial<BridgeMessageDto> | null | undefined;
  if (!o || typeof o !== 'object') throw new Error('payload must be an object');
  if (typeof o.room_id !== 'string' || !o.room_id.startsWith('!'))
    throw new Error('room_id must be a Matrix room id');
  assertAgentSlug(o.agent);
  if (typeof o.body !== 'string') throw new Error('body must be a string');
  if (o.thread_root !== undefined && typeof o.thread_root !== 'string')
    throw new Error('thread_root must be a string');
  if (
    o.extra_content !== undefined &&
    (typeof o.extra_content !== 'object' || o.extra_content === null)
  ) {
    throw new Error('extra_content must be an object');
  }
}

export function validateBridgeTyping(input: unknown): asserts input is BridgeTypingDto {
  const o = input as Partial<BridgeTypingDto> | null | undefined;
  if (!o || typeof o !== 'object') throw new Error('payload must be an object');
  if (typeof o.room_id !== 'string' || !o.room_id.startsWith('!'))
    throw new Error('room_id must be a Matrix room id');
  assertAgentSlug(o.agent);
  if (typeof o.typing !== 'boolean') throw new Error('typing must be a boolean');
}

export interface ProvisionRoomDto {
  name: string;
  alias?: string;
  topic?: string;
  invite?: string[];
  space_id?: string;
}

export function validateProvisionRoom(input: unknown): asserts input is ProvisionRoomDto {
  const o = input as Partial<ProvisionRoomDto> | null | undefined;
  if (!o || typeof o !== 'object') throw new Error('payload must be an object');
  if (typeof o.name !== 'string' || o.name.length === 0) throw new Error('name is required');
  if (o.alias !== undefined && (!/^[a-z0-9_.-]+$/.test(o.alias) || o.alias.length > 200)) {
    throw new Error('alias must match [a-z0-9_.-]+ (max 200 chars)');
  }
  if (o.invite !== undefined) {
    if (
      !Array.isArray(o.invite) ||
      o.invite.some((u) => typeof u !== 'string' || !u.startsWith('@'))
    ) {
      throw new Error('invite must be a list of Matrix user ids');
    }
    if (o.invite.length > 50) {
      throw new Error('invite list exceeds maximum of 50');
    }
  }
  if (o.space_id !== undefined && (typeof o.space_id !== 'string' || !o.space_id.startsWith('!'))) {
    throw new Error('space_id must be a Matrix room id');
  }
}
