/**
 * Event Bus Types
 *
 * Port interface for the event bus - the backbone of the hexagonal architecture.
 * EventBus is the PORT. Implementations (EventEmitterBus, RabbitMQ, etc.) are ADAPTERS.
 */

/**
 * Base interface for all domain events.
 * Every event in the system extends this.
 */
export interface DomainEvent {
  /** Event type identifier (e.g., 'process:spawned', 'server:started') */
  type: string;
  /** When the event occurred */
  timestamp: Date;
  /** Event-specific data */
  payload: unknown;
}

/**
 * Event Bus Port Interface
 *
 * All modules communicate through this interface.
 * Can be swapped for external systems (RabbitMQ, WebSocket forwarding) later.
 */
// =============================================================================
// Domain Event Types - Typed payloads for each event
// =============================================================================

/**
 * Process Events
 */

export interface ProcessSpawnedEvent extends DomainEvent {
  type: 'process:spawned';
  payload: {
    processId: string;
    pid: number;
    command: string;
  };
}

export interface ProcessStoppedEvent extends DomainEvent {
  type: 'process:stopped';
  payload: {
    processId: string;
    pid: number;
    exitCode: number | null;
  };
}

export interface ProcessCrashedEvent extends DomainEvent {
  type: 'process:crashed';
  payload: {
    processId: string;
    pid: number;
    exitCode: number | null;
    signal: string | null;
  };
}

/**
 * Server Events
 */

export interface ServerStartedEvent extends DomainEvent {
  type: 'server:started';
  payload: {
    port: number;
    host: string;
    pid: number;
  };
}

export interface ServerStoppedEvent extends DomainEvent {
  type: 'server:stopped';
  payload: {
    uptime: number;
  };
}

/**
 * Log Events
 */

export interface LogEntryEvent extends DomainEvent {
  type: 'log:entry';
  payload: {
    processId: string;
    stream: 'stdout' | 'stderr';
    data: string;
  };
}

/**
 * Git Worktree Events
 */

export interface WorktreeCreatedEvent extends DomainEvent {
  type: 'worktree:created';
  payload: {
    worktreeId: string;
    branch: string;
    path: string;
  };
}

export interface WorktreeRemovedEvent extends DomainEvent {
  type: 'worktree:removed';
  payload: {
    worktreeId: string;
    branch: string;
  };
}

export interface WorktreeMergedEvent extends DomainEvent {
  type: 'worktree:merged';
  payload: {
    worktreeId: string;
    sourceBranch: string;
    targetBranch: string;
  };
}

export interface WorktreeConflictEvent extends DomainEvent {
  type: 'worktree:conflict';
  payload: {
    worktreeId: string;
    sourceBranch: string;
    targetBranch: string;
    conflictingFiles: string[];
  };
}

/**
 * Agent Events
 */

export interface AgentSpawnedEvent extends DomainEvent {
  type: 'agent:spawned';
  payload: {
    agentId: string;
    name: string;
    taskId: string | null;
    worktreeId: string;
    provider: string;
  };
}

export interface AgentStoppedEvent extends DomainEvent {
  type: 'agent:stopped';
  payload: {
    agentId: string;
    name: string;
    taskId: string | null;
    reason:
      | 'user_requested'
      | 'task_complete'
      | 'error'
      | 'waiting_for_input'
      | 'context_complete'
      | 'plan_complete'
      | 'detail_complete'
      | 'refine_complete'
      | 'chat_complete';
  };
}

export interface AgentCrashedEvent extends DomainEvent {
  type: 'agent:crashed';
  payload: {
    agentId: string;
    name: string;
    taskId: string | null;
    error: string;
  };
}

export interface AgentResumedEvent extends DomainEvent {
  type: 'agent:resumed';
  payload: {
    agentId: string;
    name: string;
    taskId: string | null;
    sessionId: string;
  };
}

export interface AgentAccountSwitchedEvent extends DomainEvent {
  type: 'agent:account_switched';
  payload: {
    agentId: string;
    name: string;
    previousAccountId: string;
    newAccountId: string;
    reason: 'account_exhausted';
  };
}

export interface AgentWaitingEvent extends DomainEvent {
  type: 'agent:waiting';
  payload: {
    agentId: string;
    name: string;
    taskId: string | null;
    sessionId: string;
    questions: Array<{
      id: string;
      question: string;
      options?: Array<{ label: string; description?: string }>;
      multiSelect?: boolean;
    }>;
  };
}

export interface AgentDeletedEvent extends DomainEvent {
  type: 'agent:deleted';
  payload: {
    agentId: string;
    name: string;
  };
}

export interface AgentOutputEvent extends DomainEvent {
  type: 'agent:output';
  payload: {
    agentId: string;
    stream: 'stdout' | 'stderr';
    data: string;
  };
}

/**
 * Task Dispatch Events
 */

export interface TaskQueuedEvent extends DomainEvent {
  type: 'task:queued';
  payload: {
    taskId: string;
    priority: string;
    dependsOn: string[];
  };
}

export interface TaskDispatchedEvent extends DomainEvent {
  type: 'task:dispatched';
  payload: {
    taskId: string;
    agentId: string;
    agentName: string;
  };
}

export interface TaskCompletedEvent extends DomainEvent {
  type: 'task:completed';
  payload: {
    taskId: string;
    agentId: string;
    success: boolean;
    message: string;
  };
}

export interface TaskBlockedEvent extends DomainEvent {
  type: 'task:blocked';
  payload: {
    taskId: string;
    reason: string;
    blockedBy?: string[];
  };
}

/**
 * Phase Events
 */

export interface PhaseQueuedEvent extends DomainEvent {
  type: 'phase:queued';
  payload: {
    phaseId: string;
    initiativeId: string;
    dependsOn: string[];
  };
}

export interface PhaseStartedEvent extends DomainEvent {
  type: 'phase:started';
  payload: {
    phaseId: string;
    initiativeId: string;
  };
}

export interface PhaseCompletedEvent extends DomainEvent {
  type: 'phase:completed';
  payload: {
    phaseId: string;
    initiativeId: string;
    success: boolean;
    message?: string;
  };
}

export interface PhaseBlockedEvent extends DomainEvent {
  type: 'phase:blocked';
  payload: {
    phaseId: string;
    reason: string;
  };
}

export interface PhasePendingReviewEvent extends DomainEvent {
  type: 'phase:pending_review';
  payload: {
    phaseId: string;
    initiativeId: string;
  };
}

export interface PhaseChangesRequestedEvent extends DomainEvent {
  type: 'phase:changes_requested';
  payload: {
    phaseId: string;
    initiativeId: string;
    taskId: string;
    commentCount: number;
  };
}

export interface PhaseMergedEvent extends DomainEvent {
  type: 'phase:merged';
  payload: {
    phaseId: string;
    initiativeId: string;
    sourceBranch: string;
    targetBranch: string;
  };
}

export interface TaskMergedEvent extends DomainEvent {
  type: 'task:merged';
  payload: {
    taskId: string;
    phaseId: string;
    sourceBranch: string;
    targetBranch: string;
  };
}

/**
 * Merge Coordination Events
 */

export interface MergeQueuedEvent extends DomainEvent {
  type: 'merge:queued';
  payload: {
    taskId: string;
    agentId: string;
    worktreeId: string;
    priority: 'low' | 'medium' | 'high';
  };
}

export interface MergeStartedEvent extends DomainEvent {
  type: 'merge:started';
  payload: {
    taskId: string;
    agentId: string;
    worktreeId: string;
    targetBranch: string;
  };
}

export interface MergeCompletedEvent extends DomainEvent {
  type: 'merge:completed';
  payload: {
    taskId: string;
    agentId: string;
    worktreeId: string;
    targetBranch: string;
  };
}

export interface MergeConflictedEvent extends DomainEvent {
  type: 'merge:conflicted';
  payload: {
    taskId: string;
    agentId: string;
    worktreeId: string;
    targetBranch: string;
    conflictingFiles: string[];
  };
}

/**
 * Page Events
 */

export interface PageCreatedEvent extends DomainEvent {
  type: 'page:created';
  payload: {
    pageId: string;
    initiativeId: string;
    title: string;
  };
}

export interface PageUpdatedEvent extends DomainEvent {
  type: 'page:updated';
  payload: {
    pageId: string;
    initiativeId: string;
    title?: string;
  };
}

export interface PageDeletedEvent extends DomainEvent {
  type: 'page:deleted';
  payload: {
    pageId: string;
    initiativeId: string;
  };
}

/**
 * Change Set Events
 */

export interface ChangeSetCreatedEvent extends DomainEvent {
  type: 'changeset:created';
  payload: {
    changeSetId: string;
    initiativeId: string;
    agentId: string;
    mode: string;
    entryCount: number;
  };
}

export interface ChangeSetRevertedEvent extends DomainEvent {
  type: 'changeset:reverted';
  payload: {
    changeSetId: string;
    initiativeId: string;
  };
}

/**
 * Preview Events
 */

export interface PreviewBuildingEvent extends DomainEvent {
  type: 'preview:building';
  payload: {
    previewId: string;
    initiativeId: string;
    branch: string;
    gatewayPort: number;
    mode: 'preview' | 'dev';
    phaseId?: string;
  };
}

export interface PreviewReadyEvent extends DomainEvent {
  type: 'preview:ready';
  payload: {
    previewId: string;
    initiativeId: string;
    branch: string;
    gatewayPort: number;
    url: string;
    mode: 'preview' | 'dev';
    phaseId?: string;
  };
}

export interface PreviewStoppedEvent extends DomainEvent {
  type: 'preview:stopped';
  payload: {
    previewId: string;
    initiativeId: string;
  };
}

export interface PreviewFailedEvent extends DomainEvent {
  type: 'preview:failed';
  payload: {
    previewId: string;
    initiativeId: string;
    error: string;
  };
}

/**
 * Account Credential Events
 */

export interface AccountCredentialsRefreshedEvent extends DomainEvent {
  type: 'account:credentials_refreshed';
  payload: {
    accountId: string | null;
    expiresAt: number;
    previousExpiresAt: number | null;
  };
}

export interface AccountCredentialsExpiredEvent extends DomainEvent {
  type: 'account:credentials_expired';
  payload: {
    accountId: string | null;
    reason: 'token_expired' | 'refresh_failed' | 'credentials_missing';
    error: string | null;
  };
}

export interface AccountCredentialsValidatedEvent extends DomainEvent {
  type: 'account:credentials_validated';
  payload: {
    accountId: string | null;
    valid: boolean;
    expiresAt: number | null;
    wasRefreshed: boolean;
  };
}

/**
 * Inter-Agent Conversation Events
 */

export interface ConversationCreatedEvent extends DomainEvent {
  type: 'conversation:created';
  payload: {
    conversationId: string;
    fromAgentId: string;
    toAgentId: string;
  };
}

export interface ConversationAnsweredEvent extends DomainEvent {
  type: 'conversation:answered';
  payload: {
    conversationId: string;
    fromAgentId: string;
    toAgentId: string;
  };
}

/**
 * Project Sync Events
 */

export interface ProjectSyncedEvent extends DomainEvent {
  type: 'project:synced';
  payload: {
    projectId: string;
    projectName: string;
    fetched: boolean;
    fastForwarded: boolean;
  };
}

export interface ProjectSyncFailedEvent extends DomainEvent {
  type: 'project:sync_failed';
  payload: {
    projectId: string;
    projectName: string;
    error: string;
  };
}

/**
 * Initiative Review Events
 */

export interface InitiativePendingReviewEvent extends DomainEvent {
  type: 'initiative:pending_review';
  payload: {
    initiativeId: string;
    branch: string;
  };
}

export interface InitiativeReviewApprovedEvent extends DomainEvent {
  type: 'initiative:review_approved';
  payload: {
    initiativeId: string;
    branch: string;
    strategy: 'push_branch' | 'merge_and_push';
  };
}

export interface InitiativeChangesRequestedEvent extends DomainEvent {
  type: 'initiative:changes_requested';
  payload: {
    initiativeId: string;
    phaseId: string;
    taskId: string;
  };
}

/**
 * Chat Session Events
 */

export interface ChatMessageCreatedEvent extends DomainEvent {
  type: 'chat:message_created';
  payload: {
    chatSessionId: string;
    role: 'user' | 'assistant' | 'system';
  };
}

export interface ChatSessionClosedEvent extends DomainEvent {
  type: 'chat:session_closed';
  payload: {
    chatSessionId: string;
    initiativeId: string;
  };
}

/**
 * Union of all domain events - enables type-safe event handling
 */
export type DomainEventMap =
  | ProcessSpawnedEvent
  | ProcessStoppedEvent
  | ProcessCrashedEvent
  | ServerStartedEvent
  | ServerStoppedEvent
  | LogEntryEvent
  | WorktreeCreatedEvent
  | WorktreeRemovedEvent
  | WorktreeMergedEvent
  | WorktreeConflictEvent
  | AgentSpawnedEvent
  | AgentStoppedEvent
  | AgentCrashedEvent
  | AgentResumedEvent
  | AgentAccountSwitchedEvent
  | AgentDeletedEvent
  | AgentWaitingEvent
  | AgentOutputEvent
  | TaskQueuedEvent
  | TaskDispatchedEvent
  | TaskCompletedEvent
  | TaskBlockedEvent
  | PhaseQueuedEvent
  | PhaseStartedEvent
  | PhaseCompletedEvent
  | PhaseBlockedEvent
  | PhasePendingReviewEvent
  | PhaseChangesRequestedEvent
  | PhaseMergedEvent
  | TaskMergedEvent
  | MergeQueuedEvent
  | MergeStartedEvent
  | MergeCompletedEvent
  | MergeConflictedEvent
  | PageCreatedEvent
  | PageUpdatedEvent
  | PageDeletedEvent
  | ChangeSetCreatedEvent
  | ChangeSetRevertedEvent
  | AccountCredentialsRefreshedEvent
  | AccountCredentialsExpiredEvent
  | AccountCredentialsValidatedEvent
  | PreviewBuildingEvent
  | PreviewReadyEvent
  | PreviewStoppedEvent
  | PreviewFailedEvent
  | ConversationCreatedEvent
  | ConversationAnsweredEvent
  | ProjectSyncedEvent
  | ProjectSyncFailedEvent
  | ChatMessageCreatedEvent
  | ChatSessionClosedEvent
  | InitiativePendingReviewEvent
  | InitiativeReviewApprovedEvent
  | InitiativeChangesRequestedEvent;

/**
 * Event type literal union for type checking
 */
export type DomainEventType = DomainEventMap['type'];

// =============================================================================
// Event Bus Port Interface
// =============================================================================

/**
 * Event Bus Port Interface
 *
 * All modules communicate through this interface.
 * Can be swapped for external systems (RabbitMQ, WebSocket forwarding) later.
 *
 * **Delivery guarantee: at-most-once.**
 *
 * Events emitted while a client is disconnected are permanently lost.
 * Reconnecting clients receive only events emitted after reconnection.
 * React Query's `refetchOnWindowFocus` and `refetchOnReconnect` compensate
 * for missed mutations since the system uses query invalidation rather
 * than incremental state.
 */
export interface EventBus {
  /**
   * Emit an event to all subscribed handlers
   */
  emit<T extends DomainEvent>(event: T): void;

  /**
   * Subscribe to events of a specific type
   */
  on<T extends DomainEvent>(
    eventType: T['type'],
    handler: (event: T) => void
  ): void;

  /**
   * Unsubscribe from events of a specific type
   */
  off<T extends DomainEvent>(
    eventType: T['type'],
    handler: (event: T) => void
  ): void;

  /**
   * Subscribe to a single occurrence of an event type
   */
  once<T extends DomainEvent>(
    eventType: T['type'],
    handler: (event: T) => void
  ): void;
}
