// Domain types for the messaging UI. Zero imports on purpose: this file must never
// reach for a transport package. Adapters map their own DTOs onto these.

export type Membership = 'dm' | 'group' | 'channel';

export type ChannelVisibility = 'public' | 'private';

export interface Person {
  id: string;
  name: string;
  kind: 'staff' | 'customer';
}

export interface Conversation {
  threadId: string;
  title: string;
  subject: string | null;
  membership: Membership | null;
  participants: string[];
  unread: number;
  lastMessage?: string;
  lastAt?: string;
  /** Channel description (channels only). */
  topic?: string | null;
}

/**
 * Outcome of a bulk member import, reported per user so a partial result is never silent.
 * `skipped` were already members (which makes a repeat import a no-op); `failed` could not be added.
 */
export interface BulkAddResult {
  added: string[];
  skipped: string[];
  failed: string[];
}

/** A discoverable channel (from browseChannels) — includes ones the caller has NOT joined. */
export interface ChannelSummary {
  threadId: string;
  name: string;
  topic: string | null;
  visibility: ChannelVisibility;
  memberCount: number;
  /** True if the current user is already a member. */
  joined: boolean;
}

export interface CreateChannelInput {
  name: string;
  topic?: string;
  visibility: ChannelVisibility;
}

export interface Reaction {
  emoji: string;
  count: number;
  mine: boolean;
}

export interface Attachment {
  /** A resolved URL for display/download. May be empty until resolved by the host. */
  url: string;
  mime: string;
  name: string;
  /** Storage reference — carried so send() can persist the message part (upload returns it). */
  contentRef?: string;
  sizeBytes?: number;
}

export interface Message {
  id: string;
  actorId: string | null;
  text: string;
  at: string;
  parentInteractionId?: string | null;
  reactions?: Reaction[];
  attachment?: Attachment;
  /** True only when the transport is optimistic-local and not yet acknowledged. */
  pending?: boolean;
}

export interface SendOpts {
  parentInteractionId?: string;
  attachment?: Attachment;
  /** Opaque userId notify-list (from @mentions). The app parses "@"; the kernel just forwards it. */
  mentions?: string[];
}

export type MessageEvent =
  | { kind: 'message'; message: Message }
  | { kind: 'typing'; userId: string }
  | { kind: 'receipt'; messageId: string; actorId: string }
  | { kind: 'reaction'; messageId: string; reactions: Reaction[] };

export type Unsubscribe = () => void;

/** Ownership is a pure function of explicit identity — never inferred from history.
 *  See the spec: inferring it is the bug this SDK exists partly to kill. */
export function isOwnMessage(message: Message, currentActorId: string | null): boolean {
  return currentActorId !== null && message.actorId !== null && message.actorId === currentActorId;
}
