/**
 * Notification and configuration types for Hermit.
 *
 * These types define:
 * - Detected errors from session files
 * - Notification triggers (rules for when to notify)
 * - Application configuration settings
 *
 * Shared between preload and renderer processes.
 */

import type { TriggerColor } from '@shared/constants/triggerColors';

// =============================================================================
// Detected Error Types
// =============================================================================

/**
 * Team notification event sub-types.
 * Single source of truth — used by DetectedError, TeamNotificationPayload, and TEAM_NOTIFICATION_CONFIG.
 */
export type TeamEventType =
  | 'rate_limit'
  | 'lead_inbox'
  | 'user_inbox'
  | 'task_clarification'
  | 'task_status_change'
  | 'task_comment'
  | 'task_created'
  | 'all_tasks_completed'
  | 'cross_team_message'
  | 'schedule_completed'
  | 'schedule_failed'
  | 'team_launched';

/**
 * Detected error from session JSONL files.
 * Used for notification display and deep linking to error locations.
 */
export interface DetectedError {
  /** UUID for unique identification */
  id: string;
  /** Unix timestamp when error occurred */
  timestamp: number;
  /** Session ID where error occurred */
  sessionId: string;
  /** Project ID (encoded project path) */
  projectId: string;
  /** Path to the JSONL file */
  filePath: string;
  /** Tool name or 'assistant' */
  source: string;
  /** Error message text */
  message: string;
  /** Line number in JSONL for deep linking */
  lineNumber?: number;
  /** Tool use ID for precise deep linking to the specific tool item */
  toolUseId?: string;
  /** Subagent ID when error originates from a subagent session */
  subagentId?: string;
  /** Whether the notification has been read */
  isRead: boolean;
  /** When the notification was created */
  createdAt: number;
  /** Trigger color key for notification dot and highlight */
  triggerColor?: TriggerColor;
  /** ID of the trigger that produced this notification */
  triggerId?: string;
  /** Human-readable name of the trigger that produced this notification */
  triggerName?: string;
  /** Notification domain: 'error' (default/undefined) or 'team' */
  category?: 'error' | 'team';
  /** For team notifications: specific event sub-type */
  teamEventType?: TeamEventType;
  /** Explicit key for storage deduplication. Two notifications with the same dedupeKey won't be stored twice. */
  dedupeKey?: string;
  /** Additional context */
  context: {
    /** Display name of the project */
    projectName: string;
    /** Current working directory when error occurred */
    cwd?: string;
  };
}

// =============================================================================
// Notification Trigger Types
// =============================================================================

/**
 * Content types that can trigger notifications.
 */
export type TriggerContentType = 'tool_result' | 'tool_use' | 'thinking' | 'text';

/**
 * Known tool names that can be filtered for tool_use triggers.
 */
export const KNOWN_TOOL_NAMES = [
  'Bash',
  'Task',
  'TodoWrite',
  'Read',
  'Write',
  'Edit',
  'Grep',
  'Glob',
  'WebFetch',
  'WebSearch',
  'LSP',
  'Skill',
  'NotebookEdit',
  'AskUserQuestion',
  'KillShell',
  'TaskOutput',
] as const;

/**
 * Tool names that can be filtered for tool_use triggers.
 * Accepts known tool names or any custom tool name.
 */
export type TriggerToolName = (typeof KNOWN_TOOL_NAMES)[number] | (string & Record<never, never>);

/**
 * Match fields available for different content types and tools.
 */
export type MatchFieldForToolResult = 'content';
export type MatchFieldForBash = 'command' | 'description';
export type MatchFieldForTask = 'description' | 'prompt' | 'subagent_type';
export type MatchFieldForRead = 'file_path';
export type MatchFieldForWrite = 'file_path' | 'content';
export type MatchFieldForEdit = 'file_path' | 'old_string' | 'new_string';
export type MatchFieldForGlob = 'pattern' | 'path';
export type MatchFieldForGrep = 'pattern' | 'path' | 'glob';
export type MatchFieldForWebFetch = 'url' | 'prompt';
export type MatchFieldForWebSearch = 'query';
export type MatchFieldForSkill = 'skill' | 'args';
export type MatchFieldForThinking = 'thinking';
export type MatchFieldForText = 'text';

/**
 * Combined type for all possible match fields.
 */
export type TriggerMatchField =
  | MatchFieldForToolResult
  | MatchFieldForBash
  | MatchFieldForTask
  | MatchFieldForRead
  | MatchFieldForWrite
  | MatchFieldForEdit
  | MatchFieldForGlob
  | MatchFieldForGrep
  | MatchFieldForWebFetch
  | MatchFieldForWebSearch
  | MatchFieldForSkill
  | MatchFieldForThinking
  | MatchFieldForText;

/**
 * Trigger mode determines how the trigger evaluates conditions.
 * - 'error_status': Triggers when is_error is true (simple boolean check)
 * - 'content_match': Triggers when content matches a regex pattern
 * - 'token_threshold': Triggers when token count exceeds threshold
 */
export type TriggerMode = 'error_status' | 'content_match' | 'token_threshold';

/**
 * Token type for threshold triggers.
 */
export type TriggerTokenType = 'input' | 'output' | 'total';

/**
 * Notification trigger configuration.
 * Defines when notifications should be generated.
 */
export interface NotificationTrigger {
  /** Unique identifier for this trigger */
  id: string;
  /** Human-readable name for this trigger */
  name: string;
  /** Whether this trigger is enabled */
  enabled: boolean;
  /** Content type to match */
  contentType: TriggerContentType;
  /** For tool_use/tool_result: specific tool name to match */
  toolName?: TriggerToolName;
  /** Whether this is a built-in trigger (cannot be deleted) */
  isBuiltin?: boolean;
  /** Regex patterns to IGNORE (skip notification if content matches any of these) */
  ignorePatterns?: string[];

  // === Discriminated Union Mode ===
  /** Trigger evaluation mode */
  mode: TriggerMode;

  // === Mode: error_status ===
  /** For error_status mode: always triggers on is_error=true */
  requireError?: boolean;

  // === Mode: content_match ===
  /** For content_match mode: field to match against */
  matchField?: TriggerMatchField;
  /** For content_match mode: regex pattern to match */
  matchPattern?: string;

  // === Mode: token_threshold ===
  /** For token_threshold mode: minimum token count to trigger */
  tokenThreshold?: number;
  /** For token_threshold mode: which token type to check */
  tokenType?: TriggerTokenType;

  // === Repository Scope ===
  /** If set, this trigger only applies to these repository group IDs */
  repositoryIds?: string[];

  // === Display ===
  /** Color for notification dot and navigation highlight (preset key or hex string) */
  color?: TriggerColor;
}

/**
 * Result of testing a trigger against historical data.
 */
export interface TriggerTestResult {
  totalCount: number;
  errors: {
    id: string;
    sessionId: string;
    projectId: string;
    message: string;
    timestamp: number;
    source: string;
    /** Tool use ID for precise deep linking to the specific tool item */
    toolUseId?: string;
    /** Subagent ID when error originates from or targets a subagent */
    subagentId?: string;
    /** Line number in JSONL for deep linking */
    lineNumber?: number;
    context: { projectName: string };
  }[];
  /**
   * True if results were truncated due to safety limits:
   * - totalCount capped at 10,000
   * - Max 100 sessions scanned
   * - 30 second timeout
   */
  truncated?: boolean;
}

// =============================================================================
// Application Configuration Types
// =============================================================================

/**
 * Application configuration settings.
 * Persisted to disk and loaded on app startup.
 */
export interface AppConfig {
  /** Notification-related settings */
  notifications: {
    /** Whether notifications are enabled globally */
    enabled: boolean;
    /** Whether to play sound with notifications */
    soundEnabled: boolean;
    /** Regex patterns for errors to ignore */
    ignoredRegex: string[];
    /** Repository group IDs to ignore for notifications */
    ignoredRepositories: string[];
    /** Unix timestamp until which notifications are snoozed (null if not snoozed) */
    snoozedUntil: number | null;
    /** Default snooze duration in minutes */
    snoozeMinutes: number;
    /** Whether to include errors from subagent sessions */
    includeSubagentErrors: boolean;
    /** Whether to show native OS notifications when teammates send messages to the team lead */
    notifyOnLeadInbox: boolean;
    /** Whether to show native OS notifications when teammates send messages to you (the user) */
    notifyOnUserInbox: boolean;
    /** Whether to show native OS notifications when a task needs user clarification */
    notifyOnClarifications: boolean;
    /** Whether to show native OS notifications when a task status changes */
    notifyOnStatusChange: boolean;
    /** Whether to show native OS notifications when a new comment is added to a task */
    notifyOnTaskComments: boolean;
    /** Whether to show native OS notifications when a new task is created */
    notifyOnTaskCreated: boolean;
    /** Whether to show native OS notifications when all tasks in a team are completed */
    notifyOnAllTasksCompleted: boolean;
    /** Whether to show native OS notifications for cross-team messages */
    notifyOnCrossTeamMessage: boolean;
    /** Whether to show native OS notifications when a team finishes launching */
    notifyOnTeamLaunched: boolean;
    /** Whether to show native OS notifications when a tool needs user approval (Allow/Deny) */
    notifyOnToolApproval: boolean;
    /** Whether to automatically nudge a rate-limited team after the limit resets */
    autoResumeOnRateLimit: boolean;
    /** Only notify on status changes in solo teams (no teammates) */
    statusChangeOnlySolo: boolean;
    /** Which target statuses to notify about (e.g. ['in_progress', 'completed']) */
    statusChangeStatuses: string[];
    /** Notification triggers - define when to generate notifications */
    triggers: NotificationTrigger[];
  };
  /** General application settings */
  general: {
    /** Whether to launch app at system login */
    launchAtLogin: boolean;
    /** Whether to show icon in dock (macOS) */
    showDockIcon: boolean;
    /** Application theme */
    theme: 'dark' | 'light' | 'system';
    /** Default tab to show on app launch */
    defaultTab: 'dashboard' | 'last-session';
    /** Whether to use the multimodel runtime instead of the stock Claude CLI */
    multimodelEnabled: boolean;
    /** Optional custom Claude root folder (auto-detected when null) */
    claudeRootPath: string | null;
    /** Agent communication language ('system' = use OS locale) */
    agentLanguage: string;
    /** Whether to auto-expand AI response groups when opening a transcript or receiving new messages */
    autoExpandAIGroups: boolean;
    /** Whether to use the native OS title bar instead of the custom one (Linux/Windows) */
    useNativeTitleBar: boolean;
    /** Send anonymous crash & performance telemetry (requires SENTRY_DSN at build time) */
    telemetryEnabled: boolean;
  };
  /** Provider connection preferences for app-launched multimodel sessions */
  providerConnections: {
    anthropic: {
      authMode: 'auto' | 'oauth' | 'api_key';
      fastModeDefault: boolean;
    };
    codex: {
      preferredAuthMode: 'auto' | 'chatgpt' | 'api_key';
    };
  };
  /** Runtime backend preferences for app-launched agent_teams_orchestrator sessions */
  runtime: {
    providerBackends: {
      gemini: 'auto' | 'api' | 'cli-sdk';
      codex: 'codex-native';
    };
  };
  /** Display and UI settings */
  display: {
    /** Whether to show timestamps in message views */
    showTimestamps: boolean;
    /** Whether to use compact display mode */
    compactMode: boolean;
    /** Whether to enable syntax highlighting in code blocks */
    syntaxHighlighting: boolean;
  };
  /** Session-related settings */
  sessions: {
    /** Pinned sessions per project. Key is projectId, value is array of pinned sessions */
    pinnedSessions: Record<string, { sessionId: string; pinnedAt: number }[]>;
    /** Hidden sessions per project. Key is projectId, value is array of hidden sessions */
    hiddenSessions: Record<string, { sessionId: string; hiddenAt: number }[]>;
  };
  /** SSH connection settings */
  ssh?: {
    /** Last used connection details */
    lastConnection: {
      host: string;
      port: number;
      username: string;
      authMethod: 'password' | 'privateKey' | 'agent' | 'auto';
      privateKeyPath?: string;
    } | null;
    /** Whether to auto-reconnect on launch */
    autoReconnect: boolean;
    /** Saved SSH connection profiles */
    profiles: {
      id: string;
      name: string;
      host: string;
      port: number;
      username: string;
      authMethod: 'password' | 'privateKey' | 'agent' | 'auto';
      privateKeyPath?: string;
    }[];
    /** Managed machines that can run ClaudeCode remotely. */
    machines?: {
      id: string;
      name: string;
      displayName: string;
      host: string;
      port: number;
      username: string;
      authMethod: 'password' | 'privateKey' | 'agent' | 'auto';
      privateKeyPath?: string;
      claudeRoot?: string;
      workspaceRoot?: string;
      runtimeStatus?: Record<string, unknown>;
      createdAt?: string;
      updatedAt?: string;
    }[];
    /** Last active context ID */
    lastActiveContextId: string;
  };
  /** HTTP sidecar server settings for iframe embedding */
  httpServer?: {
    /** Whether the HTTP server is enabled */
    enabled: boolean;
    /** Port for the HTTP server (default 3456) */
    port: number;
  };
}
