/**
 * IPC channel names and payload types.
 * Shared between main, preload, and renderer processes.
 *
 * NOTE: This file must be browser-compatible (no Node.js imports).
 * Validation schemas are in src/main/ipc/validation.ts.
 */

import type { InitialPrompt } from "./api/types";

// ============ Branded Path Types ============

declare const ProjectPathBrand: unique symbol;
declare const WorkspacePathBrand: unique symbol;

/**
 * Branded type for project paths (git repository root directories).
 */
export type ProjectPath = string & { readonly [ProjectPathBrand]: true };

/**
 * Branded type for workspace paths (git worktree directories).
 */
export type WorkspacePath = string & { readonly [WorkspacePathBrand]: true };

// ============ Domain Types ============

// NOTE: Most domain types have been moved to src/shared/api/types.ts
// This file retains only types needed for IPC communication.

// ============ Agent Status Types ============

/**
 * Internal counts of agents in each status for aggregation.
 * This is used internally for status computation - external consumers
 * should use AgentStatusCounts from api/types.ts which includes `total`.
 */
export interface InternalAgentCounts {
  readonly idle: number;
  readonly busy: number;
}

/**
 * Aggregated agent status for a workspace (discriminated union).
 * Used internally for status aggregation.
 */
export type AggregatedAgentStatus =
  | { readonly status: "none"; readonly counts: InternalAgentCounts }
  | { readonly status: "idle"; readonly counts: InternalAgentCounts }
  | { readonly status: "busy"; readonly counts: InternalAgentCounts }
  | { readonly status: "mixed"; readonly counts: InternalAgentCounts };

// ============ UI Mode Types ============

/**
 * UI mode for the application.
 * - "workspace": Normal mode, workspace view has focus, UI behind workspace
 * - "shortcut": Shortcut mode active, UI on top, shows keyboard hints
 * - "dialog": Dialog open, UI on top, dialog has focus (blocks Alt+X)
 * - "hover": UI overlay active (sidebar hover), UI on top, no focus change (allows Alt+X)
 */
export type UIMode = "workspace" | "dialog" | "shortcut" | "hover";

/**
 * Event payload for UI mode changes.
 */
export interface UIModeChangedEvent {
  readonly mode: UIMode;
  readonly previousMode: UIMode;
}

// ============ IPC Handler Payload Types ============
// Payload types for IPC handlers registered in the UiIpc module.

/** Methods with no input - use empty object {} */
export type EmptyPayload = object;

/** projects.open */
export interface ProjectOpenPayload {
  readonly path?: string;
}

/** projects.close */
export interface ProjectClosePayload {
  readonly projectPath: string;
  /** If true and project has remoteUrl, delete the entire project directory including cloned repo */
  readonly removeLocalRepo?: boolean;
}

/** projects.clone */
export interface ProjectClonePayload {
  readonly url: string;
}

/** projects.fetchBases */
export interface ProjectPathPayload {
  readonly projectPath: string;
}

/** workspaces.create */
export interface WorkspaceCreatePayload {
  readonly projectPath: string;
  readonly name: string;
  readonly base: string;
  /** Optional initial prompt to send after workspace is created */
  readonly initialPrompt?: InitialPrompt;
  /** If true, steal focus from current workspace. If false, don't steal focus but still
   *  switch when no workspace is active. Default: switch (undefined treated as true). */
  readonly stealFocus?: boolean;
  /** Optional per-workspace agent override. When omitted, falls back to the global default. */
  readonly agent?: LifecycleAgentType;
}

/** workspaces.remove */
export interface WorkspaceRemovePayload {
  readonly workspacePath: string;
  readonly keepBranch?: boolean;
  /** If true, don't switch away from this workspace when it's active. Used for retry. */
  readonly skipSwitch?: boolean;
  /** If true, force remove (skip cleanup, ignore errors). Replaces old forceRemove. */
  readonly force?: boolean;
  /** If true, skip preflight checks for uncommitted changes and unmerged commits. */
  readonly ignoreWarnings?: boolean;
  /** PIDs from a previous failed attempt. Flush hook kills these before re-attempting delete. */
  readonly blockingPids?: readonly number[];
}

/** workspaces.getStatus */
export interface WorkspaceGetStatusPayload {
  readonly workspacePath: string;
  /** If true, fetch remotes before reading status so unmerged-commit counts
   * reflect server-merged branches. Best-effort. */
  readonly refresh?: boolean;
}

/** ui.switchWorkspace */
export interface UiSwitchWorkspacePayload {
  readonly workspacePath: string;
  readonly focus?: boolean;
}

/** ui.setMode */
export interface UiSetModePayload {
  readonly mode: UIMode;
}

// ============ API Layer IPC Channels ============
// All IPC channels use the api: prefix.
// Domain events are mapped to IPC channels by the UiIpc module.

/**
 * IPC channel names for main↔renderer communication.
 * All channels use the api: prefix convention.
 */
export const ApiIpcChannels = {
  // Project commands
  PROJECT_OPEN: "api:project:open",
  PROJECT_CLOSE: "api:project:close",
  PROJECT_CLONE: "api:project:clone",
  PROJECT_FETCH_BASES: "api:project:fetch-bases",
  // Workspace commands
  WORKSPACE_CREATE: "api:workspace:create",
  WORKSPACE_REMOVE: "api:workspace:remove",
  WORKSPACE_HIBERNATE: "api:workspace:hibernate",
  WORKSPACE_WAKE: "api:workspace:wake",
  WORKSPACE_REOPEN: "api:workspace:reopen",
  WORKSPACE_GET_SCREENSHOT: "api:workspace:get-screenshot",
  WORKSPACE_GET_STATUS: "api:workspace:get-status",
  // UI commands
  UI_SWITCH_WORKSPACE: "api:ui:switch-workspace",
  UI_SET_MODE: "api:ui:set-mode",
  // Lifecycle commands
  LIFECYCLE_READY: "api:lifecycle:ready",
  LIFECYCLE_QUIT: "api:lifecycle:quit",
  // Lifecycle events (main → renderer)
  LIFECYCLE_SHOW_MAIN_VIEW: "api:lifecycle:show-main-view",
  // Dialog framework (main ↔ renderer)
  DIALOG_COMMAND: "api:dialog:command",
  DIALOG_EVENT: "api:dialog:event",
  // Notification framework (main ↔ renderer)
  NOTIFICATION_COMMAND: "api:notification:command",
  NOTIFICATION_EVENT: "api:notification:event",
  // Log commands (renderer → main)
  LOG_DEBUG: "api:log:debug",
  LOG_INFO: "api:log:info",
  LOG_WARN: "api:log:warn",
  LOG_ERROR: "api:log:error",
  // Events (main → renderer)
  PROJECT_OPENED: "api:project:opened",
  PROJECT_CLOSED: "api:project:closed",
  PROJECT_BASES_UPDATED: "api:project:bases-updated",
  WORKSPACE_CREATED: "api:workspace:created",
  WORKSPACE_REMOVED: "api:workspace:removed",
  WORKSPACE_HIBERNATED: "api:workspace:hibernated",
  WORKSPACE_HIBERNATE_FAILED: "api:workspace:hibernate-failed",
  WORKSPACE_WOKEN: "api:workspace:woken",
  WORKSPACE_WAKE_FAILED: "api:workspace:wake-failed",
  WORKSPACE_SWITCHED: "api:workspace:switched",
  WORKSPACE_STATUS_CHANGED: "api:workspace:status-changed",
  WORKSPACE_METADATA_CHANGED: "api:workspace:metadata-changed",
  WORKSPACE_DELETION_PROGRESS: "api:workspace:deletion-progress",
  UI_MODE_CHANGED: "api:ui:mode-changed",
  UI_THEME: "api:ui:theme",
  SHORTCUT_KEY: "api:shortcut:key",
} as const satisfies Record<string, string>;

// ============ Lifecycle Event Payload Types ============

/**
 * Agent types for agent selection.
 * Mirrors ConfigAgentType from api/types.ts but defined here to avoid circular imports.
 */
export type LifecycleAgentType = "opencode" | "claude";

/**
 * Agent info for the selection dialog.
 * Provided by per-agent modules via the register-agents hook.
 */
export interface AgentInfo {
  readonly agent: LifecycleAgentType;
  readonly label: string;
  readonly icon: string;
}

// ============ Log API Types ============

/**
 * Context data for log entries.
 * Constrained to primitive types for serialization safety.
 */
export type LogContext = Record<string, string | number | boolean | null>;

/**
 * Payload for api:log:* commands.
 */
export interface ApiLogPayload {
  /** Logger name/scope (e.g., 'ui', 'api') */
  readonly logger: string;
  /** Log message */
  readonly message: string;
  /** Optional context data */
  readonly context?: LogContext;
}
