// Type definitions for Electron IPC API
import type { SessionListItem, Message } from '@/types/electron';
import type { ClaudeUsageResponse } from '@/store/app-store';
import type {
  IssueValidationVerdict,
  IssueValidationConfidence,
  IssueComplexity,
  IssueValidationInput,
  IssueValidationResult,
  IssueValidationResponse,
  IssueValidationEvent,
  StoredValidation,
  AgentModel,
} from '@automaker/types';
import { getJSON, setJSON, removeItem } from './storage';

// Re-export issue validation types for use in components
export type {
  IssueValidationVerdict,
  IssueValidationConfidence,
  IssueComplexity,
  IssueValidationInput,
  IssueValidationResult,
  IssueValidationResponse,
  IssueValidationEvent,
  StoredValidation,
};

export interface FileEntry {
  name: string;
  isDirectory: boolean;
  isFile: boolean;
}

export interface FileStats {
  isDirectory: boolean;
  isFile: boolean;
  size: number;
  mtime: Date;
}

export interface DialogResult {
  canceled: boolean;
  filePaths: string[];
}

export interface FileResult {
  success: boolean;
  content?: string;
  error?: string;
}

export interface WriteResult {
  success: boolean;
  error?: string;
}

export interface ReaddirResult {
  success: boolean;
  entries?: FileEntry[];
  error?: string;
}

export interface StatResult {
  success: boolean;
  stats?: FileStats;
  error?: string;
}

// Re-export types from electron.d.ts for external use
export type {
  AutoModeEvent,
  ModelDefinition,
  ProviderStatus,
  WorktreeAPI,
  GitAPI,
  WorktreeInfo,
  WorktreeStatus,
  FileDiffsResult,
  FileDiffResult,
  FileStatus,
} from '@/types/electron';

// Import types for internal use in this file
import type {
  AutoModeEvent,
  WorktreeAPI,
  GitAPI,
  ModelDefinition,
  ProviderStatus,
} from '@/types/electron';

// Import HTTP API client (ES module)
import { getHttpApiClient } from './http-api-client';

// Feature type - Import from app-store
import type { Feature } from '@/store/app-store';

// Running Agent type
export interface RunningAgent {
  featureId: string;
  projectPath: string;
  projectName: string;
  isAutoMode: boolean;
}

export interface RunningAgentsResult {
  success: boolean;
  runningAgents?: RunningAgent[];
  totalCount?: number;
  error?: string;
}

export interface RunningAgentsAPI {
  getAll: () => Promise<RunningAgentsResult>;
}

// GitHub types
export interface GitHubLabel {
  name: string;
  color: string;
}

export interface GitHubAuthor {
  login: string;
  avatarUrl?: string;
}

export interface GitHubAssignee {
  login: string;
  avatarUrl?: string;
}

export interface LinkedPullRequest {
  number: number;
  title: string;
  state: string;
  url: string;
}

export interface GitHubIssue {
  number: number;
  title: string;
  state: string;
  author: GitHubAuthor;
  createdAt: string;
  labels: GitHubLabel[];
  url: string;
  body: string;
  assignees: GitHubAssignee[];
  linkedPRs?: LinkedPullRequest[];
}

export interface GitHubPR {
  number: number;
  title: string;
  state: string;
  author: GitHubAuthor;
  createdAt: string;
  labels: GitHubLabel[];
  url: string;
  isDraft: boolean;
  headRefName: string;
  reviewDecision: string | null;
  mergeable: string;
  body: string;
}

export interface GitHubRemoteStatus {
  hasGitHubRemote: boolean;
  remoteUrl: string | null;
  owner: string | null;
  repo: string | null;
}

export interface GitHubAPI {
  checkRemote: (projectPath: string) => Promise<{
    success: boolean;
    hasGitHubRemote?: boolean;
    remoteUrl?: string | null;
    owner?: string | null;
    repo?: string | null;
    error?: string;
  }>;
  listIssues: (projectPath: string) => Promise<{
    success: boolean;
    openIssues?: GitHubIssue[];
    closedIssues?: GitHubIssue[];
    error?: string;
  }>;
  listPRs: (projectPath: string) => Promise<{
    success: boolean;
    openPRs?: GitHubPR[];
    mergedPRs?: GitHubPR[];
    error?: string;
  }>;
  /** Start async validation of a GitHub issue */
  validateIssue: (
    projectPath: string,
    issue: IssueValidationInput,
    model?: AgentModel
  ) => Promise<{ success: boolean; message?: string; issueNumber?: number; error?: string }>;
  /** Check validation status for an issue or all issues */
  getValidationStatus: (
    projectPath: string,
    issueNumber?: number
  ) => Promise<{
    success: boolean;
    isRunning?: boolean;
    startedAt?: string;
    runningIssues?: number[];
    error?: string;
  }>;
  /** Stop a running validation */
  stopValidation: (
    projectPath: string,
    issueNumber: number
  ) => Promise<{ success: boolean; message?: string; error?: string }>;
  /** Get stored validations for a project */
  getValidations: (
    projectPath: string,
    issueNumber?: number
  ) => Promise<{
    success: boolean;
    validation?: StoredValidation | null;
    validations?: StoredValidation[];
    isStale?: boolean;
    error?: string;
  }>;
  /** Mark a validation as viewed by the user */
  markValidationViewed: (
    projectPath: string,
    issueNumber: number
  ) => Promise<{ success: boolean; error?: string }>;
  /** Subscribe to validation events */
  onValidationEvent: (callback: (event: IssueValidationEvent) => void) => () => void;
}

// Feature Suggestions types
export interface FeatureSuggestion {
  id: string;
  category: string;
  description: string;
  priority: number;
  reasoning: string;
}

export interface SuggestionsEvent {
  type: 'suggestions_progress' | 'suggestions_tool' | 'suggestions_complete' | 'suggestions_error';
  content?: string;
  tool?: string;
  input?: unknown;
  suggestions?: FeatureSuggestion[];
  error?: string;
}

export type SuggestionType = 'features' | 'refactoring' | 'security' | 'performance';

export interface SuggestionsAPI {
  generate: (
    projectPath: string,
    suggestionType?: SuggestionType
  ) => Promise<{ success: boolean; error?: string }>;
  stop: () => Promise<{ success: boolean; error?: string }>;
  status: () => Promise<{
    success: boolean;
    isRunning?: boolean;
    error?: string;
  }>;
  onEvent: (callback: (event: SuggestionsEvent) => void) => () => void;
}

// Spec Regeneration types
export type SpecRegenerationEvent =
  | { type: 'spec_regeneration_progress'; content: string; projectPath: string }
  | {
      type: 'spec_regeneration_tool';
      tool: string;
      input: unknown;
      projectPath: string;
    }
  | { type: 'spec_regeneration_complete'; message: string; projectPath: string }
  | { type: 'spec_regeneration_error'; error: string; projectPath: string };

export interface SpecRegenerationAPI {
  create: (
    projectPath: string,
    projectOverview: string,
    generateFeatures?: boolean,
    analyzeProject?: boolean,
    maxFeatures?: number
  ) => Promise<{ success: boolean; error?: string }>;
  generate: (
    projectPath: string,
    projectDefinition: string,
    generateFeatures?: boolean,
    analyzeProject?: boolean,
    maxFeatures?: number
  ) => Promise<{ success: boolean; error?: string }>;
  generateFeatures: (
    projectPath: string,
    maxFeatures?: number
  ) => Promise<{
    success: boolean;
    error?: string;
  }>;
  stop: () => Promise<{ success: boolean; error?: string }>;
  status: () => Promise<{
    success: boolean;
    isRunning?: boolean;
    currentPhase?: string;
    error?: string;
  }>;
  onEvent: (callback: (event: SpecRegenerationEvent) => void) => () => void;
}

// Features API types
export interface FeaturesAPI {
  getAll: (
    projectPath: string
  ) => Promise<{ success: boolean; features?: Feature[]; error?: string }>;
  get: (
    projectPath: string,
    featureId: string
  ) => Promise<{ success: boolean; feature?: Feature; error?: string }>;
  create: (
    projectPath: string,
    feature: Feature
  ) => Promise<{ success: boolean; feature?: Feature; error?: string }>;
  update: (
    projectPath: string,
    featureId: string,
    updates: Partial<Feature>
  ) => Promise<{ success: boolean; feature?: Feature; error?: string }>;
  delete: (projectPath: string, featureId: string) => Promise<{ success: boolean; error?: string }>;
  getAgentOutput: (
    projectPath: string,
    featureId: string
  ) => Promise<{ success: boolean; content?: string | null; error?: string }>;
  generateTitle: (
    description: string
  ) => Promise<{ success: boolean; title?: string; error?: string }>;
}

export interface AutoModeAPI {
  start: (
    projectPath: string,
    maxConcurrency?: number
  ) => Promise<{ success: boolean; error?: string }>;
  stop: (
    projectPath: string
  ) => Promise<{ success: boolean; error?: string; runningFeatures?: number }>;
  stopFeature: (featureId: string) => Promise<{ success: boolean; error?: string }>;
  status: (projectPath?: string) => Promise<{
    success: boolean;
    isRunning?: boolean;
    currentFeatureId?: string | null;
    runningFeatures?: string[];
    runningProjects?: string[];
    runningCount?: number;
    error?: string;
  }>;
  runFeature: (
    projectPath: string,
    featureId: string,
    useWorktrees?: boolean,
    worktreePath?: string
  ) => Promise<{ success: boolean; passes?: boolean; error?: string }>;
  verifyFeature: (
    projectPath: string,
    featureId: string
  ) => Promise<{ success: boolean; passes?: boolean; error?: string }>;
  resumeFeature: (
    projectPath: string,
    featureId: string,
    useWorktrees?: boolean
  ) => Promise<{ success: boolean; passes?: boolean; error?: string }>;
  contextExists: (
    projectPath: string,
    featureId: string
  ) => Promise<{ success: boolean; exists?: boolean; error?: string }>;
  analyzeProject: (
    projectPath: string
  ) => Promise<{ success: boolean; message?: string; error?: string }>;
  followUpFeature: (
    projectPath: string,
    featureId: string,
    prompt: string,
    imagePaths?: string[],
    worktreePath?: string
  ) => Promise<{ success: boolean; passes?: boolean; error?: string }>;
  commitFeature: (
    projectPath: string,
    featureId: string,
    worktreePath?: string
  ) => Promise<{ success: boolean; error?: string }>;
  approvePlan: (
    projectPath: string,
    featureId: string,
    approved: boolean,
    editedPlan?: string,
    feedback?: string
  ) => Promise<{ success: boolean; error?: string }>;
  onEvent: (callback: (event: AutoModeEvent) => void) => () => void;
}

export interface SaveImageResult {
  success: boolean;
  path?: string;
  error?: string;
}

export interface ElectronAPI {
  ping: () => Promise<string>;
  openExternalLink: (url: string) => Promise<{ success: boolean; error?: string }>;
  openDirectory: () => Promise<DialogResult>;
  openFile: (options?: object) => Promise<DialogResult>;
  readFile: (filePath: string) => Promise<FileResult>;
  writeFile: (filePath: string, content: string) => Promise<WriteResult>;
  mkdir: (dirPath: string) => Promise<WriteResult>;
  readdir: (dirPath: string) => Promise<ReaddirResult>;
  exists: (filePath: string) => Promise<boolean>;
  stat: (filePath: string) => Promise<StatResult>;
  deleteFile: (filePath: string) => Promise<WriteResult>;
  trashItem?: (filePath: string) => Promise<WriteResult>;
  getPath: (name: string) => Promise<string>;
  openInEditor?: (
    filePath: string,
    line?: number,
    column?: number
  ) => Promise<{ success: boolean; error?: string }>;
  saveImageToTemp?: (
    data: string,
    filename: string,
    mimeType: string,
    projectPath?: string
  ) => Promise<SaveImageResult>;
  checkClaudeCli?: () => Promise<{
    success: boolean;
    status?: string;
    method?: string;
    version?: string;
    path?: string;
    recommendation?: string;
    installCommands?: {
      macos?: string;
      windows?: string;
      linux?: string;
      npm?: string;
    };
    error?: string;
  }>;
  model?: {
    getAvailable: () => Promise<{
      success: boolean;
      models?: ModelDefinition[];
      error?: string;
    }>;
    checkProviders: () => Promise<{
      success: boolean;
      providers?: Record<string, ProviderStatus>;
      error?: string;
    }>;
  };
  worktree?: WorktreeAPI;
  git?: GitAPI;
  suggestions?: SuggestionsAPI;
  specRegeneration?: SpecRegenerationAPI;
  autoMode?: AutoModeAPI;
  features?: FeaturesAPI;
  runningAgents?: RunningAgentsAPI;
  github?: GitHubAPI;
  enhancePrompt?: {
    enhance: (
      originalText: string,
      enhancementMode: string,
      model?: string
    ) => Promise<{
      success: boolean;
      enhancedText?: string;
      error?: string;
    }>;
  };
  setup?: {
    getClaudeStatus: () => Promise<{
      success: boolean;
      status?: string;
      installed?: boolean;
      method?: string;
      version?: string;
      path?: string;
      auth?: {
        authenticated: boolean;
        method: string;
        hasCredentialsFile?: boolean;
        hasToken?: boolean;
        hasStoredOAuthToken?: boolean;
        hasStoredApiKey?: boolean;
        hasEnvApiKey?: boolean;
        hasEnvOAuthToken?: boolean;
      };
      error?: string;
    }>;
    installClaude: () => Promise<{
      success: boolean;
      message?: string;
      error?: string;
    }>;
    authClaude: () => Promise<{
      success: boolean;
      token?: string;
      requiresManualAuth?: boolean;
      terminalOpened?: boolean;
      command?: string;
      error?: string;
      message?: string;
      output?: string;
    }>;
    storeApiKey: (
      provider: string,
      apiKey: string
    ) => Promise<{ success: boolean; error?: string }>;
    deleteApiKey: (
      provider: string
    ) => Promise<{ success: boolean; error?: string; message?: string }>;
    getApiKeys: () => Promise<{
      success: boolean;
      hasAnthropicKey: boolean;
      hasGoogleKey: boolean;
    }>;
    getPlatform: () => Promise<{
      success: boolean;
      platform: string;
      arch: string;
      homeDir: string;
      isWindows: boolean;
      isMac: boolean;
      isLinux: boolean;
    }>;
    verifyClaudeAuth: (authMethod?: 'cli' | 'api_key') => Promise<{
      success: boolean;
      authenticated: boolean;
      error?: string;
    }>;
    getGhStatus?: () => Promise<{
      success: boolean;
      installed: boolean;
      authenticated: boolean;
      version: string | null;
      path: string | null;
      user: string | null;
      error?: string;
    }>;
    onInstallProgress?: (callback: (progress: any) => void) => () => void;
    onAuthProgress?: (callback: (progress: any) => void) => () => void;
  };
  agent?: {
    start: (
      sessionId: string,
      workingDirectory?: string
    ) => Promise<{
      success: boolean;
      messages?: Message[];
      error?: string;
    }>;
    send: (
      sessionId: string,
      message: string,
      workingDirectory?: string,
      imagePaths?: string[],
      model?: string
    ) => Promise<{ success: boolean; error?: string }>;
    getHistory: (sessionId: string) => Promise<{
      success: boolean;
      messages?: Message[];
      isRunning?: boolean;
      error?: string;
    }>;
    stop: (sessionId: string) => Promise<{ success: boolean; error?: string }>;
    clear: (sessionId: string) => Promise<{ success: boolean; error?: string }>;
    onStream: (callback: (data: unknown) => void) => () => void;
  };
  sessions?: {
    list: (includeArchived?: boolean) => Promise<{
      success: boolean;
      sessions?: SessionListItem[];
      error?: string;
    }>;
    create: (
      name: string,
      projectPath: string,
      workingDirectory?: string
    ) => Promise<{
      success: boolean;
      session?: {
        id: string;
        name: string;
        projectPath: string;
        workingDirectory?: string;
        createdAt: string;
        updatedAt: string;
      };
      error?: string;
    }>;
    update: (
      sessionId: string,
      name?: string,
      tags?: string[]
    ) => Promise<{ success: boolean; error?: string }>;
    archive: (sessionId: string) => Promise<{ success: boolean; error?: string }>;
    unarchive: (sessionId: string) => Promise<{ success: boolean; error?: string }>;
    delete: (sessionId: string) => Promise<{ success: boolean; error?: string }>;
  };
  claude?: {
    getUsage: () => Promise<ClaudeUsageResponse>;
  };
  context?: {
    describeImage: (imagePath: string) => Promise<{
      success: boolean;
      description?: string;
      error?: string;
    }>;
    describeFile: (filePath: string) => Promise<{
      success: boolean;
      description?: string;
      error?: string;
    }>;
  };
}

// Note: Window interface is declared in @/types/electron.d.ts
// Do not redeclare here to avoid type conflicts

// Mock data for web development
const mockFeatures = [
  {
    category: 'Core',
    description: 'Sample Feature',
    steps: ['Step 1', 'Step 2'],
    passes: false,
  },
];

// Local storage keys
const STORAGE_KEYS = {
  PROJECTS: 'automaker_projects',
  CURRENT_PROJECT: 'automaker_current_project',
  TRASHED_PROJECTS: 'automaker_trashed_projects',
} as const;

// Mock file system using localStorage
const mockFileSystem: Record<string, string> = {};

// Check if we're in Electron (for UI indicators only)
export const isElectron = (): boolean => {
  if (typeof window === 'undefined') {
    return false;
  }

  if ((window as any).isElectron === true) {
    return true;
  }

  return window.electronAPI?.isElectron === true;
};

// Check if backend server is available
let serverAvailable: boolean | null = null;
let serverCheckPromise: Promise<boolean> | null = null;

export const checkServerAvailable = async (): Promise<boolean> => {
  if (serverAvailable !== null) return serverAvailable;
  if (serverCheckPromise) return serverCheckPromise;

  serverCheckPromise = (async () => {
    try {
      const serverUrl = import.meta.env.VITE_SERVER_URL || 'http://localhost:3008';
      const response = await fetch(`${serverUrl}/api/health`, {
        method: 'GET',
        signal: AbortSignal.timeout(2000),
      });
      serverAvailable = response.ok;
    } catch {
      serverAvailable = false;
    }
    return serverAvailable;
  })();

  return serverCheckPromise;
};

// Reset server check (useful for retrying connection)
export const resetServerCheck = (): void => {
  serverAvailable = null;
  serverCheckPromise = null;
};

// Cached HTTP client instance
let httpClientInstance: ElectronAPI | null = null;

/**
 * Get the HTTP API client
 *
 * All API calls go through HTTP to the backend server.
 * This is the only transport mode supported.
 */
export const getElectronAPI = (): ElectronAPI => {
  if (typeof window === 'undefined') {
    throw new Error('Cannot get API during SSR');
  }

  if (!httpClientInstance) {
    httpClientInstance = getHttpApiClient();
  }
  return httpClientInstance!;
};

// Async version (same as sync since HTTP client is synchronously instantiated)
export const getElectronAPIAsync = async (): Promise<ElectronAPI> => {
  return getElectronAPI();
};

// Check if backend is connected (for showing connection status in UI)
export const isBackendConnected = async (): Promise<boolean> => {
  return await checkServerAvailable();
};

/**
 * Get the current API mode being used
 * Always returns "http" since that's the only mode now
 */
export const getCurrentApiMode = (): 'http' => {
  return 'http';
};

// Debug helpers
if (typeof window !== 'undefined') {
  (window as any).__checkApiMode = () => {
    console.log('Current API mode:', getCurrentApiMode());
    console.log('isElectron():', isElectron());
  };
}

// Mock API for development/fallback when no backend is available
const getMockElectronAPI = (): ElectronAPI => {
  return {
    ping: async () => 'pong (mock)',

    openExternalLink: async (url: string) => {
      // In web mode, open in a new tab
      window.open(url, '_blank', 'noopener,noreferrer');
      return { success: true };
    },

    openDirectory: async () => {
      // In web mode, we'll use a prompt to simulate directory selection
      const path = prompt('Enter project directory path:', '/Users/demo/project');
      return {
        canceled: !path,
        filePaths: path ? [path] : [],
      };
    },

    openFile: async () => {
      const path = prompt('Enter file path:');
      return {
        canceled: !path,
        filePaths: path ? [path] : [],
      };
    },

    readFile: async (filePath: string) => {
      // Check mock file system first
      if (mockFileSystem[filePath] !== undefined) {
        return { success: true, content: mockFileSystem[filePath] };
      }
      // Return mock data based on file type
      // Note: Features are now stored in .automaker/features/{id}/feature.json
      if (filePath.endsWith('categories.json')) {
        // Return empty array for categories when file doesn't exist yet
        return { success: true, content: '[]' };
      }
      if (filePath.endsWith('app_spec.txt')) {
        return {
          success: true,
          content:
            '<project_specification>\n  <project_name>Demo Project</project_name>\n</project_specification>',
        };
      }
      // For any file in mock features directory, check mock file system
      if (filePath.includes('.automaker/features/')) {
        if (mockFileSystem[filePath] !== undefined) {
          return { success: true, content: mockFileSystem[filePath] };
        }
        // Return empty string for agent-output.md if it doesn't exist
        if (filePath.endsWith('/agent-output.md')) {
          return { success: true, content: '' };
        }
      }
      return { success: false, error: 'File not found (mock)' };
    },

    writeFile: async (filePath: string, content: string) => {
      mockFileSystem[filePath] = content;
      return { success: true };
    },

    mkdir: async () => {
      return { success: true };
    },

    readdir: async (dirPath: string) => {
      // Return mock directory structure based on path
      if (dirPath) {
        // Check if this is the context directory - return files from mock file system
        if (dirPath.includes('.automaker/context')) {
          const contextFiles = Object.keys(mockFileSystem)
            .filter((path) => path.startsWith(dirPath) && path !== dirPath)
            .map((path) => {
              const name = path.substring(dirPath.length + 1); // +1 for the trailing slash
              return {
                name,
                isDirectory: false,
                isFile: true,
              };
            })
            .filter((entry) => !entry.name.includes('/')); // Only direct children
          return { success: true, entries: contextFiles };
        }
        // Root level
        if (
          !dirPath.includes('/src') &&
          !dirPath.includes('/tests') &&
          !dirPath.includes('/public') &&
          !dirPath.includes('.automaker')
        ) {
          return {
            success: true,
            entries: [
              { name: 'src', isDirectory: true, isFile: false },
              { name: 'tests', isDirectory: true, isFile: false },
              { name: 'public', isDirectory: true, isFile: false },
              { name: '.automaker', isDirectory: true, isFile: false },
              { name: 'package.json', isDirectory: false, isFile: true },
              { name: 'tsconfig.json', isDirectory: false, isFile: true },
              { name: 'app_spec.txt', isDirectory: false, isFile: true },
              { name: 'features', isDirectory: true, isFile: false },
              { name: 'README.md', isDirectory: false, isFile: true },
            ],
          };
        }
        // src directory
        if (dirPath.endsWith('/src')) {
          return {
            success: true,
            entries: [
              { name: 'components', isDirectory: true, isFile: false },
              { name: 'lib', isDirectory: true, isFile: false },
              { name: 'app', isDirectory: true, isFile: false },
              { name: 'index.ts', isDirectory: false, isFile: true },
              { name: 'utils.ts', isDirectory: false, isFile: true },
            ],
          };
        }
        // src/components directory
        if (dirPath.endsWith('/components')) {
          return {
            success: true,
            entries: [
              { name: 'Button.tsx', isDirectory: false, isFile: true },
              { name: 'Card.tsx', isDirectory: false, isFile: true },
              { name: 'Header.tsx', isDirectory: false, isFile: true },
              { name: 'Footer.tsx', isDirectory: false, isFile: true },
            ],
          };
        }
        // src/lib directory
        if (dirPath.endsWith('/lib')) {
          return {
            success: true,
            entries: [
              { name: 'api.ts', isDirectory: false, isFile: true },
              { name: 'helpers.ts', isDirectory: false, isFile: true },
            ],
          };
        }
        // src/app directory
        if (dirPath.endsWith('/app')) {
          return {
            success: true,
            entries: [
              { name: 'page.tsx', isDirectory: false, isFile: true },
              { name: 'layout.tsx', isDirectory: false, isFile: true },
              { name: 'globals.css', isDirectory: false, isFile: true },
            ],
          };
        }
        // tests directory
        if (dirPath.endsWith('/tests')) {
          return {
            success: true,
            entries: [
              { name: 'unit.test.ts', isDirectory: false, isFile: true },
              { name: 'e2e.spec.ts', isDirectory: false, isFile: true },
            ],
          };
        }
        // public directory
        if (dirPath.endsWith('/public')) {
          return {
            success: true,
            entries: [
              { name: 'favicon.ico', isDirectory: false, isFile: true },
              { name: 'logo.svg', isDirectory: false, isFile: true },
            ],
          };
        }
        // Default empty for other paths
        return { success: true, entries: [] };
      }
      return { success: true, entries: [] };
    },

    exists: async (filePath: string) => {
      // Check if file exists in mock file system (including newly created files)
      if (mockFileSystem[filePath] !== undefined) {
        return true;
      }
      // Note: Features are now stored in .automaker/features/{id}/feature.json
      if (filePath.endsWith('app_spec.txt') && !filePath.includes('.automaker')) {
        return true;
      }
      return false;
    },

    stat: async () => {
      return {
        success: true,
        stats: {
          isDirectory: false,
          isFile: true,
          size: 1024,
          mtime: new Date(),
        },
      };
    },

    deleteFile: async (filePath: string) => {
      delete mockFileSystem[filePath];
      return { success: true };
    },

    trashItem: async () => {
      return { success: true };
    },

    getPath: async (name: string) => {
      if (name === 'userData') {
        return '/mock/userData';
      }
      return `/mock/${name}`;
    },

    // Save image to temp directory
    saveImageToTemp: async (
      data: string,
      filename: string,
      mimeType: string,
      projectPath?: string
    ) => {
      // Generate a mock temp file path - use projectPath if provided
      const timestamp = Date.now();
      const safeName = filename.replace(/[^a-zA-Z0-9.-]/g, '_');
      const tempFilePath = projectPath
        ? `${projectPath}/.automaker/images/${timestamp}_${safeName}`
        : `/tmp/automaker-images/${timestamp}_${safeName}`;

      // Store the image data in mock file system for testing
      mockFileSystem[tempFilePath] = data;

      console.log('[Mock] Saved image to temp:', tempFilePath);
      return { success: true, path: tempFilePath };
    },

    checkClaudeCli: async () => ({
      success: false,
      status: 'not_installed',
      recommendation: 'Claude CLI checks are unavailable in the web preview.',
    }),

    model: {
      getAvailable: async () => ({ success: true, models: [] }),
      checkProviders: async () => ({ success: true, providers: {} }),
    },

    // Mock Setup API
    setup: createMockSetupAPI(),

    // Mock Auto Mode API
    autoMode: createMockAutoModeAPI(),

    // Mock Worktree API
    worktree: createMockWorktreeAPI(),

    // Mock Git API (for non-worktree operations)
    git: createMockGitAPI(),

    // Mock Suggestions API
    suggestions: createMockSuggestionsAPI(),

    // Mock Spec Regeneration API
    specRegeneration: createMockSpecRegenerationAPI(),

    // Mock Features API
    features: createMockFeaturesAPI(),

    // Mock Running Agents API
    runningAgents: createMockRunningAgentsAPI(),

    // Mock GitHub API
    github: createMockGitHubAPI(),

    // Mock Claude API
    claude: {
      getUsage: async () => {
        console.log('[Mock] Getting Claude usage');
        return {
          sessionTokensUsed: 0,
          sessionLimit: 0,
          sessionPercentage: 15,
          sessionResetTime: new Date(Date.now() + 3600000).toISOString(),
          sessionResetText: 'Resets in 1h',
          weeklyTokensUsed: 0,
          weeklyLimit: 0,
          weeklyPercentage: 5,
          weeklyResetTime: new Date(Date.now() + 86400000 * 2).toISOString(),
          weeklyResetText: 'Resets Dec 23',
          sonnetWeeklyTokensUsed: 0,
          sonnetWeeklyPercentage: 1,
          sonnetResetText: 'Resets Dec 27',
          costUsed: null,
          costLimit: null,
          costCurrency: null,
          lastUpdated: new Date().toISOString(),
          userTimezone: 'UTC',
        };
      },
    },
  };
};

// Setup API interface
interface SetupAPI {
  getClaudeStatus: () => Promise<{
    success: boolean;
    status?: string;
    installed?: boolean;
    method?: string;
    version?: string;
    path?: string;
    auth?: {
      authenticated: boolean;
      method: string;
      hasCredentialsFile?: boolean;
      hasToken?: boolean;
      hasStoredOAuthToken?: boolean;
      hasStoredApiKey?: boolean;
      hasEnvApiKey?: boolean;
      hasEnvOAuthToken?: boolean;
      hasCliAuth?: boolean;
      hasRecentActivity?: boolean;
    };
    error?: string;
  }>;
  installClaude: () => Promise<{
    success: boolean;
    message?: string;
    error?: string;
  }>;
  authClaude: () => Promise<{
    success: boolean;
    token?: string;
    requiresManualAuth?: boolean;
    terminalOpened?: boolean;
    command?: string;
    error?: string;
    message?: string;
    output?: string;
  }>;
  storeApiKey: (provider: string, apiKey: string) => Promise<{ success: boolean; error?: string }>;
  getApiKeys: () => Promise<{
    success: boolean;
    hasAnthropicKey: boolean;
    hasGoogleKey: boolean;
  }>;
  deleteApiKey: (
    provider: string
  ) => Promise<{ success: boolean; error?: string; message?: string }>;
  getPlatform: () => Promise<{
    success: boolean;
    platform: string;
    arch: string;
    homeDir: string;
    isWindows: boolean;
    isMac: boolean;
    isLinux: boolean;
  }>;
  verifyClaudeAuth: (authMethod?: 'cli' | 'api_key') => Promise<{
    success: boolean;
    authenticated: boolean;
    error?: string;
  }>;
  getGhStatus?: () => Promise<{
    success: boolean;
    installed: boolean;
    authenticated: boolean;
    version: string | null;
    path: string | null;
    user: string | null;
    error?: string;
  }>;
  onInstallProgress?: (callback: (progress: any) => void) => () => void;
  onAuthProgress?: (callback: (progress: any) => void) => () => void;
}

// Mock Setup API implementation
function createMockSetupAPI(): SetupAPI {
  return {
    getClaudeStatus: async () => {
      console.log('[Mock] Getting Claude status');
      return {
        success: true,
        status: 'not_installed',
        installed: false,
        auth: {
          authenticated: false,
          method: 'none',
          hasCredentialsFile: false,
          hasToken: false,
          hasCliAuth: false,
          hasRecentActivity: false,
        },
      };
    },

    installClaude: async () => {
      console.log('[Mock] Installing Claude CLI');
      // Simulate installation delay
      await new Promise((resolve) => setTimeout(resolve, 1000));
      return {
        success: false,
        error:
          'CLI installation is only available in the Electron app. Please run the command manually.',
      };
    },

    authClaude: async () => {
      console.log('[Mock] Auth Claude CLI');
      return {
        success: true,
        requiresManualAuth: true,
        command: 'claude login',
      };
    },

    storeApiKey: async (provider: string, apiKey: string) => {
      console.log('[Mock] Storing API key for:', provider);
      // In mock mode, we just pretend to store it (it's already in the app store)
      return { success: true };
    },

    getApiKeys: async () => {
      console.log('[Mock] Getting API keys');
      return {
        success: true,
        hasAnthropicKey: false,
        hasGoogleKey: false,
      };
    },

    deleteApiKey: async (provider: string) => {
      console.log('[Mock] Deleting API key for:', provider);
      return { success: true, message: `API key for ${provider} deleted` };
    },

    getPlatform: async () => {
      return {
        success: true,
        platform: 'darwin',
        arch: 'arm64',
        homeDir: '/Users/mock',
        isWindows: false,
        isMac: true,
        isLinux: false,
      };
    },

    verifyClaudeAuth: async (authMethod?: 'cli' | 'api_key') => {
      console.log('[Mock] Verifying Claude auth with method:', authMethod);
      // Mock always returns not authenticated
      return {
        success: true,
        authenticated: false,
        error: 'Mock environment - authentication not available',
      };
    },

    getGhStatus: async () => {
      console.log('[Mock] Getting GitHub CLI status');
      return {
        success: true,
        installed: false,
        authenticated: false,
        version: null,
        path: null,
        user: null,
      };
    },

    onInstallProgress: (callback) => {
      // Mock progress events
      return () => {};
    },

    onAuthProgress: (callback) => {
      // Mock auth events
      return () => {};
    },
  };
}

// Mock Worktree API implementation
function createMockWorktreeAPI(): WorktreeAPI {
  return {
    mergeFeature: async (projectPath: string, featureId: string, options?: object) => {
      console.log('[Mock] Merging feature:', {
        projectPath,
        featureId,
        options,
      });
      return { success: true, mergedBranch: `feature/${featureId}` };
    },

    getInfo: async (projectPath: string, featureId: string) => {
      console.log('[Mock] Getting worktree info:', { projectPath, featureId });
      return {
        success: true,
        worktreePath: `/mock/worktrees/${featureId}`,
        branchName: `feature/${featureId}`,
        head: 'abc1234',
      };
    },

    getStatus: async (projectPath: string, featureId: string) => {
      console.log('[Mock] Getting worktree status:', {
        projectPath,
        featureId,
      });
      return {
        success: true,
        modifiedFiles: 3,
        files: ['src/feature.ts', 'tests/feature.spec.ts', 'README.md'],
        diffStat: ' 3 files changed, 50 insertions(+), 10 deletions(-)',
        recentCommits: ['abc1234 feat: implement feature', 'def5678 test: add tests for feature'],
      };
    },

    list: async (projectPath: string) => {
      console.log('[Mock] Listing worktrees:', { projectPath });
      return { success: true, worktrees: [] };
    },

    listAll: async (projectPath: string, includeDetails?: boolean) => {
      console.log('[Mock] Listing all worktrees:', {
        projectPath,
        includeDetails,
      });
      return {
        success: true,
        worktrees: [
          {
            path: projectPath,
            branch: 'main',
            isMain: true,
            isCurrent: true,
            hasWorktree: true,
            hasChanges: false,
            changedFilesCount: 0,
          },
        ],
      };
    },

    create: async (projectPath: string, branchName: string, baseBranch?: string) => {
      console.log('[Mock] Creating worktree:', {
        projectPath,
        branchName,
        baseBranch,
      });
      return {
        success: true,
        worktree: {
          path: `${projectPath}/.worktrees/${branchName}`,
          branch: branchName,
          isNew: true,
        },
      };
    },

    delete: async (projectPath: string, worktreePath: string, deleteBranch?: boolean) => {
      console.log('[Mock] Deleting worktree:', {
        projectPath,
        worktreePath,
        deleteBranch,
      });
      return {
        success: true,
        deleted: {
          worktreePath,
          branch: deleteBranch ? 'feature-branch' : null,
        },
      };
    },

    commit: async (worktreePath: string, message: string) => {
      console.log('[Mock] Committing changes:', { worktreePath, message });
      return {
        success: true,
        result: {
          committed: true,
          commitHash: 'abc123',
          branch: 'feature-branch',
          message,
        },
      };
    },

    push: async (worktreePath: string, force?: boolean) => {
      console.log('[Mock] Pushing worktree:', { worktreePath, force });
      return {
        success: true,
        result: {
          branch: 'feature-branch',
          pushed: true,
          message: 'Successfully pushed to origin/feature-branch',
        },
      };
    },

    createPR: async (worktreePath: string, options?: any) => {
      console.log('[Mock] Creating PR:', { worktreePath, options });
      return {
        success: true,
        result: {
          branch: 'feature-branch',
          committed: true,
          commitHash: 'abc123',
          pushed: true,
          prUrl: 'https://github.com/example/repo/pull/1',
          prCreated: true,
        },
      };
    },

    getDiffs: async (projectPath: string, featureId: string) => {
      console.log('[Mock] Getting file diffs:', { projectPath, featureId });
      return {
        success: true,
        diff: "diff --git a/src/feature.ts b/src/feature.ts\n+++ new file\n@@ -0,0 +1,10 @@\n+export function feature() {\n+  return 'hello';\n+}",
        files: [
          { status: 'A', path: 'src/feature.ts', statusText: 'Added' },
          { status: 'M', path: 'README.md', statusText: 'Modified' },
        ],
        hasChanges: true,
      };
    },

    getFileDiff: async (projectPath: string, featureId: string, filePath: string) => {
      console.log('[Mock] Getting file diff:', {
        projectPath,
        featureId,
        filePath,
      });
      return {
        success: true,
        diff: `diff --git a/${filePath} b/${filePath}\n+++ new file\n@@ -0,0 +1,5 @@\n+// New content`,
        filePath,
      };
    },

    pull: async (worktreePath: string) => {
      console.log('[Mock] Pulling latest changes for:', worktreePath);
      return {
        success: true,
        result: {
          branch: 'main',
          pulled: true,
          message: 'Pulled latest changes',
        },
      };
    },

    checkoutBranch: async (worktreePath: string, branchName: string) => {
      console.log('[Mock] Creating and checking out branch:', {
        worktreePath,
        branchName,
      });
      return {
        success: true,
        result: {
          previousBranch: 'main',
          newBranch: branchName,
          message: `Created and checked out branch '${branchName}'`,
        },
      };
    },

    listBranches: async (worktreePath: string) => {
      console.log('[Mock] Listing branches for:', worktreePath);
      return {
        success: true,
        result: {
          currentBranch: 'main',
          branches: [
            { name: 'main', isCurrent: true, isRemote: false },
            { name: 'develop', isCurrent: false, isRemote: false },
            { name: 'feature/example', isCurrent: false, isRemote: false },
          ],
          aheadCount: 2,
          behindCount: 0,
        },
      };
    },

    switchBranch: async (worktreePath: string, branchName: string) => {
      console.log('[Mock] Switching to branch:', { worktreePath, branchName });
      return {
        success: true,
        result: {
          previousBranch: 'main',
          currentBranch: branchName,
          message: `Switched to branch '${branchName}'`,
        },
      };
    },

    openInEditor: async (worktreePath: string) => {
      console.log('[Mock] Opening in editor:', worktreePath);
      return {
        success: true,
        result: {
          message: `Opened ${worktreePath} in VS Code`,
          editorName: 'VS Code',
        },
      };
    },

    getDefaultEditor: async () => {
      console.log('[Mock] Getting default editor');
      return {
        success: true,
        result: {
          editorName: 'VS Code',
          editorCommand: 'code',
        },
      };
    },

    initGit: async (projectPath: string) => {
      console.log('[Mock] Initializing git:', projectPath);
      return {
        success: true,
        result: {
          initialized: true,
          message: `Initialized git repository in ${projectPath}`,
        },
      };
    },

    startDevServer: async (projectPath: string, worktreePath: string) => {
      console.log('[Mock] Starting dev server:', { projectPath, worktreePath });
      return {
        success: true,
        result: {
          worktreePath,
          port: 3001,
          url: 'http://localhost:3001',
          message: 'Dev server started on port 3001',
        },
      };
    },

    stopDevServer: async (worktreePath: string) => {
      console.log('[Mock] Stopping dev server:', worktreePath);
      return {
        success: true,
        result: {
          worktreePath,
          message: 'Dev server stopped',
        },
      };
    },

    listDevServers: async () => {
      console.log('[Mock] Listing dev servers');
      return {
        success: true,
        result: {
          servers: [],
        },
      };
    },

    getPRInfo: async (worktreePath: string, branchName: string) => {
      console.log('[Mock] Getting PR info:', { worktreePath, branchName });
      return {
        success: true,
        result: {
          hasPR: false,
          ghCliAvailable: false,
        },
      };
    },
  };
}

// Mock Git API implementation (for non-worktree operations)
function createMockGitAPI(): GitAPI {
  return {
    getDiffs: async (projectPath: string) => {
      console.log('[Mock] Getting git diffs for project:', { projectPath });
      return {
        success: true,
        diff: "diff --git a/src/feature.ts b/src/feature.ts\n+++ new file\n@@ -0,0 +1,10 @@\n+export function feature() {\n+  return 'hello';\n+}",
        files: [
          { status: 'A', path: 'src/feature.ts', statusText: 'Added' },
          { status: 'M', path: 'README.md', statusText: 'Modified' },
        ],
        hasChanges: true,
      };
    },

    getFileDiff: async (projectPath: string, filePath: string) => {
      console.log('[Mock] Getting git file diff:', { projectPath, filePath });
      return {
        success: true,
        diff: `diff --git a/${filePath} b/${filePath}\n+++ new file\n@@ -0,0 +1,5 @@\n+// New content`,
        filePath,
      };
    },
  };
}

// Mock Auto Mode state and implementation
let mockAutoModeRunning = false;
let mockRunningFeatures = new Set<string>(); // Track multiple concurrent feature verifications
let mockAutoModeCallbacks: ((event: AutoModeEvent) => void)[] = [];
let mockAutoModeTimeouts = new Map<string, NodeJS.Timeout>(); // Track timeouts per feature

function createMockAutoModeAPI(): AutoModeAPI {
  return {
    start: async (projectPath: string, maxConcurrency?: number) => {
      if (mockAutoModeRunning) {
        return { success: false, error: 'Auto mode is already running' };
      }

      mockAutoModeRunning = true;
      console.log(`[Mock] Auto mode started with maxConcurrency: ${maxConcurrency || 3}`);
      const featureId = 'auto-mode-0';
      mockRunningFeatures.add(featureId);

      // Simulate auto mode with Plan-Act-Verify phases
      simulateAutoModeLoop(projectPath, featureId);

      return { success: true };
    },

    stop: async (_projectPath: string) => {
      mockAutoModeRunning = false;
      const runningCount = mockRunningFeatures.size;
      mockRunningFeatures.clear();
      // Clear all timeouts
      mockAutoModeTimeouts.forEach((timeout) => clearTimeout(timeout));
      mockAutoModeTimeouts.clear();
      return { success: true, runningFeatures: runningCount };
    },

    stopFeature: async (featureId: string) => {
      if (!mockRunningFeatures.has(featureId)) {
        return { success: false, error: `Feature ${featureId} is not running` };
      }

      // Clear the timeout for this specific feature
      const timeout = mockAutoModeTimeouts.get(featureId);
      if (timeout) {
        clearTimeout(timeout);
        mockAutoModeTimeouts.delete(featureId);
      }

      // Remove from running features
      mockRunningFeatures.delete(featureId);

      // Emit a stopped event
      emitAutoModeEvent({
        type: 'auto_mode_feature_complete',
        featureId,
        passes: false,
        message: 'Feature stopped by user',
      });

      return { success: true };
    },

    status: async (_projectPath?: string) => {
      return {
        success: true,
        isRunning: mockAutoModeRunning,
        currentFeatureId: mockAutoModeRunning ? 'feature-0' : null,
        runningFeatures: Array.from(mockRunningFeatures),
        runningCount: mockRunningFeatures.size,
      };
    },

    runFeature: async (
      projectPath: string,
      featureId: string,
      useWorktrees?: boolean,
      worktreePath?: string
    ) => {
      if (mockRunningFeatures.has(featureId)) {
        return {
          success: false,
          error: `Feature ${featureId} is already running`,
        };
      }

      console.log(
        `[Mock] Running feature ${featureId} with useWorktrees: ${useWorktrees}, worktreePath: ${worktreePath}`
      );
      mockRunningFeatures.add(featureId);
      simulateAutoModeLoop(projectPath, featureId);

      return { success: true, passes: true };
    },

    verifyFeature: async (projectPath: string, featureId: string) => {
      if (mockRunningFeatures.has(featureId)) {
        return {
          success: false,
          error: `Feature ${featureId} is already running`,
        };
      }

      mockRunningFeatures.add(featureId);
      simulateAutoModeLoop(projectPath, featureId);

      return { success: true, passes: true };
    },

    resumeFeature: async (projectPath: string, featureId: string, useWorktrees?: boolean) => {
      if (mockRunningFeatures.has(featureId)) {
        return {
          success: false,
          error: `Feature ${featureId} is already running`,
        };
      }

      mockRunningFeatures.add(featureId);
      simulateAutoModeLoop(projectPath, featureId);

      return { success: true, passes: true };
    },

    contextExists: async (projectPath: string, featureId: string) => {
      // Mock implementation - simulate that context exists for some features
      // Now checks for agent-output.md in the feature's folder
      const exists =
        mockFileSystem[`${projectPath}/.automaker/features/${featureId}/agent-output.md`] !==
        undefined;
      return { success: true, exists };
    },

    analyzeProject: async (projectPath: string) => {
      // Simulate project analysis
      const analysisId = `project-analysis-${Date.now()}`;
      mockRunningFeatures.add(analysisId);

      // Emit start event
      emitAutoModeEvent({
        type: 'auto_mode_feature_start',
        featureId: analysisId,
        feature: {
          id: analysisId,
          category: 'Project Analysis',
          description: 'Analyzing project structure and tech stack',
        },
      });

      // Simulate analysis phases
      await delay(300, analysisId);
      if (!mockRunningFeatures.has(analysisId))
        return { success: false, message: 'Analysis aborted' };

      emitAutoModeEvent({
        type: 'auto_mode_phase',
        featureId: analysisId,
        phase: 'planning',
        message: 'Scanning project structure...',
      });

      emitAutoModeEvent({
        type: 'auto_mode_progress',
        featureId: analysisId,
        content: 'Starting project analysis...\n',
      });

      await delay(500, analysisId);
      if (!mockRunningFeatures.has(analysisId))
        return { success: false, message: 'Analysis aborted' };

      emitAutoModeEvent({
        type: 'auto_mode_tool',
        featureId: analysisId,
        tool: 'Glob',
        input: { pattern: '**/*' },
      });

      await delay(300, analysisId);
      if (!mockRunningFeatures.has(analysisId))
        return { success: false, message: 'Analysis aborted' };

      emitAutoModeEvent({
        type: 'auto_mode_progress',
        featureId: analysisId,
        content: 'Detected tech stack: Next.js, TypeScript, Tailwind CSS\n',
      });

      await delay(300, analysisId);
      if (!mockRunningFeatures.has(analysisId))
        return { success: false, message: 'Analysis aborted' };

      // Write mock app_spec.txt
      mockFileSystem[`${projectPath}/.automaker/app_spec.txt`] = `<project_specification>
  <project_name>Demo Project</project_name>

  <overview>
    A demo project analyzed by the Automaker AI agent.
  </overview>

  <technology_stack>
    <frontend>
      <framework>Next.js</framework>
      <language>TypeScript</language>
      <styling>Tailwind CSS</styling>
    </frontend>
  </technology_stack>

  <core_capabilities>
    - Web application
    - Component-based architecture
  </core_capabilities>

  <implemented_features>
    - Basic page structure
    - Component library
  </implemented_features>
</project_specification>`;

      // Note: Features are now stored in .automaker/features/{id}/feature.json

      emitAutoModeEvent({
        type: 'auto_mode_phase',
        featureId: analysisId,
        phase: 'verification',
        message: 'Project analysis complete',
      });

      emitAutoModeEvent({
        type: 'auto_mode_feature_complete',
        featureId: analysisId,
        passes: true,
        message: 'Project analyzed successfully',
      });

      mockRunningFeatures.delete(analysisId);
      mockAutoModeTimeouts.delete(analysisId);

      return { success: true, message: 'Project analyzed successfully' };
    },

    followUpFeature: async (
      projectPath: string,
      featureId: string,
      prompt: string,
      imagePaths?: string[],
      worktreePath?: string
    ) => {
      if (mockRunningFeatures.has(featureId)) {
        return {
          success: false,
          error: `Feature ${featureId} is already running`,
        };
      }

      console.log('[Mock] Follow-up feature:', {
        featureId,
        prompt,
        imagePaths,
      });

      mockRunningFeatures.add(featureId);

      // Simulate follow-up work (similar to run but with additional context)
      // Note: We don't await this - it runs in the background like the real implementation
      simulateAutoModeLoop(projectPath, featureId);

      // Return immediately so the modal can close (matches real implementation)
      return { success: true };
    },

    commitFeature: async (projectPath: string, featureId: string, worktreePath?: string) => {
      console.log('[Mock] Committing feature:', {
        projectPath,
        featureId,
        worktreePath,
      });

      // Simulate commit operation
      emitAutoModeEvent({
        type: 'auto_mode_feature_start',
        featureId,
        feature: {
          id: featureId,
          category: 'Commit',
          description: 'Committing changes',
        },
      });

      await delay(300, featureId);

      emitAutoModeEvent({
        type: 'auto_mode_phase',
        featureId,
        phase: 'action',
        message: 'Committing changes to git...',
      });

      await delay(500, featureId);

      emitAutoModeEvent({
        type: 'auto_mode_feature_complete',
        featureId,
        passes: true,
        message: 'Changes committed successfully',
      });

      return { success: true };
    },

    approvePlan: async (
      projectPath: string,
      featureId: string,
      approved: boolean,
      editedPlan?: string,
      feedback?: string
    ) => {
      console.log('[Mock] Plan approval:', {
        projectPath,
        featureId,
        approved,
        editedPlan: editedPlan ? '[edited]' : undefined,
        feedback,
      });
      return { success: true };
    },

    onEvent: (callback: (event: AutoModeEvent) => void) => {
      mockAutoModeCallbacks.push(callback);
      return () => {
        mockAutoModeCallbacks = mockAutoModeCallbacks.filter((cb) => cb !== callback);
      };
    },
  };
}

function emitAutoModeEvent(event: AutoModeEvent) {
  mockAutoModeCallbacks.forEach((cb) => cb(event));
}

async function simulateAutoModeLoop(projectPath: string, featureId: string) {
  const mockFeature = {
    id: featureId,
    category: 'Core',
    description: 'Sample Feature',
    steps: ['Step 1', 'Step 2'],
    passes: false,
  };

  // Start feature
  emitAutoModeEvent({
    type: 'auto_mode_feature_start',
    featureId,
    feature: mockFeature,
  });

  await delay(300, featureId);
  if (!mockRunningFeatures.has(featureId)) return;

  // Phase 1: PLANNING
  emitAutoModeEvent({
    type: 'auto_mode_phase',
    featureId,
    phase: 'planning',
    message: `Planning implementation for: ${mockFeature.description}`,
  });

  emitAutoModeEvent({
    type: 'auto_mode_progress',
    featureId,
    content: 'Analyzing codebase structure and creating implementation plan...',
  });

  await delay(500, featureId);
  if (!mockRunningFeatures.has(featureId)) return;

  // Phase 2: ACTION
  emitAutoModeEvent({
    type: 'auto_mode_phase',
    featureId,
    phase: 'action',
    message: `Executing implementation for: ${mockFeature.description}`,
  });

  emitAutoModeEvent({
    type: 'auto_mode_progress',
    featureId,
    content: 'Starting code implementation...',
  });

  await delay(300, featureId);
  if (!mockRunningFeatures.has(featureId)) return;

  // Simulate tool use
  emitAutoModeEvent({
    type: 'auto_mode_tool',
    featureId,
    tool: 'Read',
    input: { file: 'package.json' },
  });

  await delay(300, featureId);
  if (!mockRunningFeatures.has(featureId)) return;

  emitAutoModeEvent({
    type: 'auto_mode_tool',
    featureId,
    tool: 'Write',
    input: { file: 'src/feature.ts', content: '// Feature code' },
  });

  await delay(500, featureId);
  if (!mockRunningFeatures.has(featureId)) return;

  // Phase 3: VERIFICATION
  emitAutoModeEvent({
    type: 'auto_mode_phase',
    featureId,
    phase: 'verification',
    message: `Verifying implementation for: ${mockFeature.description}`,
  });

  emitAutoModeEvent({
    type: 'auto_mode_progress',
    featureId,
    content: 'Verifying implementation and checking test results...',
  });

  await delay(500, featureId);
  if (!mockRunningFeatures.has(featureId)) return;

  emitAutoModeEvent({
    type: 'auto_mode_progress',
    featureId,
    content: '✓ Verification successful: All tests passed',
  });

  // Feature complete
  emitAutoModeEvent({
    type: 'auto_mode_feature_complete',
    featureId,
    passes: true,
    message: 'Feature implemented successfully',
  });

  // Delete context file when feature is verified (matches real auto-mode-service behavior)
  // Now uses features/{id}/agent-output.md path
  const contextFilePath = `${projectPath}/.automaker/features/${featureId}/agent-output.md`;
  delete mockFileSystem[contextFilePath];

  // Clean up this feature from running set
  mockRunningFeatures.delete(featureId);
  mockAutoModeTimeouts.delete(featureId);
}

function delay(ms: number, featureId: string): Promise<void> {
  return new Promise((resolve) => {
    const timeout = setTimeout(resolve, ms);
    mockAutoModeTimeouts.set(featureId, timeout);
  });
}

// Mock Suggestions state and implementation
let mockSuggestionsRunning = false;
let mockSuggestionsCallbacks: ((event: SuggestionsEvent) => void)[] = [];
let mockSuggestionsTimeout: NodeJS.Timeout | null = null;

function createMockSuggestionsAPI(): SuggestionsAPI {
  return {
    generate: async (projectPath: string, suggestionType: SuggestionType = 'features') => {
      if (mockSuggestionsRunning) {
        return {
          success: false,
          error: 'Suggestions generation is already running',
        };
      }

      mockSuggestionsRunning = true;
      console.log(`[Mock] Generating ${suggestionType} suggestions for: ${projectPath}`);

      // Simulate async suggestion generation
      simulateSuggestionsGeneration(suggestionType);

      return { success: true };
    },

    stop: async () => {
      mockSuggestionsRunning = false;
      if (mockSuggestionsTimeout) {
        clearTimeout(mockSuggestionsTimeout);
        mockSuggestionsTimeout = null;
      }
      return { success: true };
    },

    status: async () => {
      return {
        success: true,
        isRunning: mockSuggestionsRunning,
      };
    },

    onEvent: (callback: (event: SuggestionsEvent) => void) => {
      mockSuggestionsCallbacks.push(callback);
      return () => {
        mockSuggestionsCallbacks = mockSuggestionsCallbacks.filter((cb) => cb !== callback);
      };
    },
  };
}

function emitSuggestionsEvent(event: SuggestionsEvent) {
  mockSuggestionsCallbacks.forEach((cb) => cb(event));
}

async function simulateSuggestionsGeneration(suggestionType: SuggestionType = 'features') {
  const typeLabels: Record<SuggestionType, string> = {
    features: 'feature suggestions',
    refactoring: 'refactoring opportunities',
    security: 'security vulnerabilities',
    performance: 'performance issues',
  };

  // Emit progress events
  emitSuggestionsEvent({
    type: 'suggestions_progress',
    content: `Starting project analysis for ${typeLabels[suggestionType]}...\n`,
  });

  await new Promise((resolve) => {
    mockSuggestionsTimeout = setTimeout(resolve, 500);
  });
  if (!mockSuggestionsRunning) return;

  emitSuggestionsEvent({
    type: 'suggestions_tool',
    tool: 'Glob',
    input: { pattern: '**/*.{ts,tsx,js,jsx}' },
  });

  await new Promise((resolve) => {
    mockSuggestionsTimeout = setTimeout(resolve, 500);
  });
  if (!mockSuggestionsRunning) return;

  emitSuggestionsEvent({
    type: 'suggestions_progress',
    content: 'Analyzing codebase structure...\n',
  });

  await new Promise((resolve) => {
    mockSuggestionsTimeout = setTimeout(resolve, 500);
  });
  if (!mockSuggestionsRunning) return;

  emitSuggestionsEvent({
    type: 'suggestions_progress',
    content: `Identifying ${typeLabels[suggestionType]}...\n`,
  });

  await new Promise((resolve) => {
    mockSuggestionsTimeout = setTimeout(resolve, 500);
  });
  if (!mockSuggestionsRunning) return;

  // Generate mock suggestions based on type
  let mockSuggestions: FeatureSuggestion[];

  switch (suggestionType) {
    case 'refactoring':
      mockSuggestions = [
        {
          id: `suggestion-${Date.now()}-0`,
          category: 'Code Smell',
          description: 'Extract duplicate validation logic into reusable utility',
          priority: 1,
          reasoning: 'Reduces code duplication and improves maintainability',
        },
        {
          id: `suggestion-${Date.now()}-1`,
          category: 'Complexity',
          description: 'Break down large handleSubmit function into smaller functions',
          priority: 2,
          reasoning: 'Function is too long and handles multiple responsibilities',
        },
        {
          id: `suggestion-${Date.now()}-2`,
          category: 'Architecture',
          description: 'Move business logic out of React components into hooks',
          priority: 3,
          reasoning: 'Improves separation of concerns and testability',
        },
      ];
      break;

    case 'security':
      mockSuggestions = [
        {
          id: `suggestion-${Date.now()}-0`,
          category: 'High',
          description: 'Sanitize user input before rendering to prevent XSS',
          priority: 1,
          reasoning: 'User input is rendered without proper sanitization',
        },
        {
          id: `suggestion-${Date.now()}-1`,
          category: 'Medium',
          description: 'Add rate limiting to authentication endpoints',
          priority: 2,
          reasoning: 'Prevents brute force attacks on authentication',
        },
        {
          id: `suggestion-${Date.now()}-2`,
          category: 'Low',
          description: 'Remove sensitive information from error messages',
          priority: 3,
          reasoning: 'Error messages may leak implementation details',
        },
      ];
      break;

    case 'performance':
      mockSuggestions = [
        {
          id: `suggestion-${Date.now()}-0`,
          category: 'Rendering',
          description: 'Add React.memo to prevent unnecessary re-renders',
          priority: 1,
          reasoning: "Components re-render even when props haven't changed",
        },
        {
          id: `suggestion-${Date.now()}-1`,
          category: 'Bundle Size',
          description: 'Implement code splitting for route components',
          priority: 2,
          reasoning: 'Initial bundle is larger than necessary',
        },
        {
          id: `suggestion-${Date.now()}-2`,
          category: 'Caching',
          description: 'Add memoization for expensive computations',
          priority: 3,
          reasoning: 'Expensive computations run on every render',
        },
      ];
      break;

    default: // "features"
      mockSuggestions = [
        {
          id: `suggestion-${Date.now()}-0`,
          category: 'User Experience',
          description: 'Add dark mode toggle with system preference detection',
          priority: 1,
          reasoning: 'Dark mode is a standard feature that improves accessibility and user comfort',
        },
        {
          id: `suggestion-${Date.now()}-1`,
          category: 'Performance',
          description: 'Implement lazy loading for heavy components',
          priority: 2,
          reasoning: 'Improves initial load time and reduces bundle size',
        },
        {
          id: `suggestion-${Date.now()}-2`,
          category: 'Accessibility',
          description: 'Add keyboard navigation support throughout the app',
          priority: 3,
          reasoning: 'Improves accessibility for users who rely on keyboard navigation',
        },
      ];
  }

  emitSuggestionsEvent({
    type: 'suggestions_complete',
    suggestions: mockSuggestions,
  });

  mockSuggestionsRunning = false;
  mockSuggestionsTimeout = null;
}

// Mock Spec Regeneration state and implementation
let mockSpecRegenerationRunning = false;
let mockSpecRegenerationPhase = '';
let mockSpecRegenerationCallbacks: ((event: SpecRegenerationEvent) => void)[] = [];
let mockSpecRegenerationTimeout: NodeJS.Timeout | null = null;

function createMockSpecRegenerationAPI(): SpecRegenerationAPI {
  return {
    create: async (
      projectPath: string,
      projectOverview: string,
      generateFeatures = true,
      _analyzeProject?: boolean,
      maxFeatures?: number
    ) => {
      if (mockSpecRegenerationRunning) {
        return { success: false, error: 'Spec creation is already running' };
      }

      mockSpecRegenerationRunning = true;
      console.log(
        `[Mock] Creating initial spec for: ${projectPath}, generateFeatures: ${generateFeatures}, maxFeatures: ${maxFeatures}`
      );

      // Simulate async spec creation
      simulateSpecCreation(projectPath, projectOverview, generateFeatures);

      return { success: true };
    },

    generate: async (
      projectPath: string,
      projectDefinition: string,
      generateFeatures = false,
      _analyzeProject?: boolean,
      maxFeatures?: number
    ) => {
      if (mockSpecRegenerationRunning) {
        return {
          success: false,
          error: 'Spec regeneration is already running',
        };
      }

      mockSpecRegenerationRunning = true;
      console.log(
        `[Mock] Regenerating spec for: ${projectPath}, generateFeatures: ${generateFeatures}, maxFeatures: ${maxFeatures}`
      );

      // Simulate async spec regeneration
      simulateSpecRegeneration(projectPath, projectDefinition, generateFeatures);

      return { success: true };
    },

    generateFeatures: async (projectPath: string, maxFeatures?: number) => {
      if (mockSpecRegenerationRunning) {
        return {
          success: false,
          error: 'Feature generation is already running',
        };
      }

      mockSpecRegenerationRunning = true;
      console.log(
        `[Mock] Generating features from existing spec for: ${projectPath}, maxFeatures: ${maxFeatures}`
      );

      // Simulate async feature generation
      simulateFeatureGeneration(projectPath);

      return { success: true };
    },

    stop: async () => {
      mockSpecRegenerationRunning = false;
      mockSpecRegenerationPhase = '';
      if (mockSpecRegenerationTimeout) {
        clearTimeout(mockSpecRegenerationTimeout);
        mockSpecRegenerationTimeout = null;
      }
      return { success: true };
    },

    status: async () => {
      return {
        success: true,
        isRunning: mockSpecRegenerationRunning,
        currentPhase: mockSpecRegenerationPhase,
      };
    },

    onEvent: (callback: (event: SpecRegenerationEvent) => void) => {
      mockSpecRegenerationCallbacks.push(callback);
      return () => {
        mockSpecRegenerationCallbacks = mockSpecRegenerationCallbacks.filter(
          (cb) => cb !== callback
        );
      };
    },
  };
}

function emitSpecRegenerationEvent(event: SpecRegenerationEvent) {
  mockSpecRegenerationCallbacks.forEach((cb) => cb(event));
}

async function simulateSpecCreation(
  projectPath: string,
  projectOverview: string,
  generateFeatures = true
) {
  mockSpecRegenerationPhase = 'initialization';
  emitSpecRegenerationEvent({
    type: 'spec_regeneration_progress',
    content: '[Phase: initialization] Starting project analysis...\n',
    projectPath: projectPath,
  });

  await new Promise((resolve) => {
    mockSpecRegenerationTimeout = setTimeout(resolve, 500);
  });
  if (!mockSpecRegenerationRunning) return;

  mockSpecRegenerationPhase = 'setup';
  emitSpecRegenerationEvent({
    type: 'spec_regeneration_tool',
    tool: 'Glob',
    input: { pattern: '**/*.{json,ts,tsx}' },
    projectPath: projectPath,
  });

  await new Promise((resolve) => {
    mockSpecRegenerationTimeout = setTimeout(resolve, 500);
  });
  if (!mockSpecRegenerationRunning) return;

  mockSpecRegenerationPhase = 'analysis';
  emitSpecRegenerationEvent({
    type: 'spec_regeneration_progress',
    content: '[Phase: analysis] Detecting tech stack...\n',
    projectPath: projectPath,
  });

  await new Promise((resolve) => {
    mockSpecRegenerationTimeout = setTimeout(resolve, 500);
  });
  if (!mockSpecRegenerationRunning) return;

  // Write mock app_spec.txt
  mockFileSystem[`${projectPath}/.automaker/app_spec.txt`] = `<project_specification>
  <project_name>Demo Project</project_name>

  <overview>
    ${projectOverview}
  </overview>

  <technology_stack>
    <frontend>
      <framework>Next.js</framework>
      <ui_library>React</ui_library>
      <styling>Tailwind CSS</styling>
    </frontend>
  </technology_stack>

  <core_capabilities>
    <feature_1>Core functionality based on overview</feature_1>
  </core_capabilities>

  <implementation_roadmap>
    <phase_1_foundation>Setup and basic structure</phase_1_foundation>
    <phase_2_core_logic>Core features implementation</phase_2_core_logic>
  </implementation_roadmap>
</project_specification>`;

  // Note: Features are now stored in .automaker/features/{id}/feature.json
  // The generateFeatures parameter is kept for API compatibility but features
  // should be created through the features API

  mockSpecRegenerationPhase = 'complete';
  emitSpecRegenerationEvent({
    type: 'spec_regeneration_complete',
    message: 'All tasks completed!',
    projectPath: projectPath,
  });

  mockSpecRegenerationRunning = false;
  mockSpecRegenerationPhase = '';
  mockSpecRegenerationTimeout = null;
}

async function simulateSpecRegeneration(
  projectPath: string,
  projectDefinition: string,
  generateFeatures = false
) {
  mockSpecRegenerationPhase = 'initialization';
  emitSpecRegenerationEvent({
    type: 'spec_regeneration_progress',
    content: '[Phase: initialization] Starting spec regeneration...\n',
    projectPath: projectPath,
  });

  await new Promise((resolve) => {
    mockSpecRegenerationTimeout = setTimeout(resolve, 500);
  });
  if (!mockSpecRegenerationRunning) return;

  mockSpecRegenerationPhase = 'analysis';
  emitSpecRegenerationEvent({
    type: 'spec_regeneration_progress',
    content: '[Phase: analysis] Analyzing codebase...\n',
    projectPath: projectPath,
  });

  await new Promise((resolve) => {
    mockSpecRegenerationTimeout = setTimeout(resolve, 500);
  });
  if (!mockSpecRegenerationRunning) return;

  // Write regenerated spec
  mockFileSystem[`${projectPath}/.automaker/app_spec.txt`] = `<project_specification>
  <project_name>Regenerated Project</project_name>

  <overview>
    ${projectDefinition}
  </overview>

  <technology_stack>
    <frontend>
      <framework>Next.js</framework>
      <ui_library>React</ui_library>
      <styling>Tailwind CSS</styling>
    </frontend>
  </technology_stack>

  <core_capabilities>
    <feature_1>Regenerated features based on definition</feature_1>
  </core_capabilities>
</project_specification>`;

  if (generateFeatures) {
    mockSpecRegenerationPhase = 'spec_complete';
    emitSpecRegenerationEvent({
      type: 'spec_regeneration_progress',
      content: '[Phase: spec_complete] Spec regenerated! Generating features...\n',
      projectPath: projectPath,
    });

    await new Promise((resolve) => {
      mockSpecRegenerationTimeout = setTimeout(resolve, 500);
    });
    if (!mockSpecRegenerationRunning) return;

    // Simulate feature generation
    await simulateFeatureGeneration(projectPath);
    if (!mockSpecRegenerationRunning) return;
  }

  mockSpecRegenerationPhase = 'complete';
  emitSpecRegenerationEvent({
    type: 'spec_regeneration_complete',
    message: 'All tasks completed!',
    projectPath: projectPath,
  });

  mockSpecRegenerationRunning = false;
  mockSpecRegenerationPhase = '';
  mockSpecRegenerationTimeout = null;
}

async function simulateFeatureGeneration(projectPath: string) {
  mockSpecRegenerationPhase = 'initialization';
  emitSpecRegenerationEvent({
    type: 'spec_regeneration_progress',
    content: '[Phase: initialization] Starting feature generation from existing app_spec.txt...\n',
    projectPath: projectPath,
  });

  await new Promise((resolve) => {
    mockSpecRegenerationTimeout = setTimeout(resolve, 500);
  });
  if (!mockSpecRegenerationRunning) return;

  emitSpecRegenerationEvent({
    type: 'spec_regeneration_progress',
    content: '[Phase: feature_generation] Reading implementation roadmap...\n',
    projectPath: projectPath,
  });

  await new Promise((resolve) => {
    mockSpecRegenerationTimeout = setTimeout(resolve, 500);
  });
  if (!mockSpecRegenerationRunning) return;

  mockSpecRegenerationPhase = 'feature_generation';
  emitSpecRegenerationEvent({
    type: 'spec_regeneration_progress',
    content: '[Phase: feature_generation] Creating features from roadmap...\n',
    projectPath: projectPath,
  });

  await new Promise((resolve) => {
    mockSpecRegenerationTimeout = setTimeout(resolve, 1000);
  });
  if (!mockSpecRegenerationRunning) return;

  mockSpecRegenerationPhase = 'complete';
  emitSpecRegenerationEvent({
    type: 'spec_regeneration_progress',
    content: '[Phase: complete] All tasks completed!\n',
    projectPath: projectPath,
  });

  emitSpecRegenerationEvent({
    type: 'spec_regeneration_complete',
    message: 'All tasks completed!',
    projectPath: projectPath,
  });

  mockSpecRegenerationRunning = false;
  mockSpecRegenerationPhase = '';
  mockSpecRegenerationTimeout = null;
}

// Mock Features API implementation
function createMockFeaturesAPI(): FeaturesAPI {
  // Store features in mock file system using features/{id}/feature.json pattern
  return {
    getAll: async (projectPath: string) => {
      console.log('[Mock] Getting all features for:', projectPath);

      // Check if test has set mock features via global variable
      const testFeatures = (window as any).__mockFeatures;
      if (testFeatures !== undefined) {
        return { success: true, features: testFeatures };
      }

      // Try to read from mock file system
      const featuresDir = `${projectPath}/.automaker/features`;
      const features: Feature[] = [];

      // Simulate reading feature folders
      const featureKeys = Object.keys(mockFileSystem).filter(
        (key) => key.startsWith(featuresDir) && key.endsWith('/feature.json')
      );

      for (const key of featureKeys) {
        try {
          const content = mockFileSystem[key];
          if (content) {
            const feature = JSON.parse(content);
            features.push(feature);
          }
        } catch (error) {
          console.error('[Mock] Failed to parse feature:', error);
        }
      }

      // Fallback to mock features if no features found
      if (features.length === 0) {
        return { success: true, features: mockFeatures };
      }

      return { success: true, features };
    },

    get: async (projectPath: string, featureId: string) => {
      console.log('[Mock] Getting feature:', { projectPath, featureId });
      const featurePath = `${projectPath}/.automaker/features/${featureId}/feature.json`;
      const content = mockFileSystem[featurePath];
      if (content) {
        return { success: true, feature: JSON.parse(content) };
      }
      return { success: false, error: 'Feature not found' };
    },

    create: async (projectPath: string, feature: Feature) => {
      console.log('[Mock] Creating feature:', {
        projectPath,
        featureId: feature.id,
      });
      const featurePath = `${projectPath}/.automaker/features/${feature.id}/feature.json`;
      mockFileSystem[featurePath] = JSON.stringify(feature, null, 2);
      return { success: true, feature };
    },

    update: async (projectPath: string, featureId: string, updates: Partial<Feature>) => {
      console.log('[Mock] Updating feature:', {
        projectPath,
        featureId,
        updates,
      });
      const featurePath = `${projectPath}/.automaker/features/${featureId}/feature.json`;
      const existing = mockFileSystem[featurePath];
      if (!existing) {
        return { success: false, error: 'Feature not found' };
      }
      const feature = { ...JSON.parse(existing), ...updates };
      mockFileSystem[featurePath] = JSON.stringify(feature, null, 2);
      return { success: true, feature };
    },

    delete: async (projectPath: string, featureId: string) => {
      console.log('[Mock] Deleting feature:', { projectPath, featureId });
      const featurePath = `${projectPath}/.automaker/features/${featureId}/feature.json`;
      delete mockFileSystem[featurePath];
      // Also delete agent-output.md if it exists
      const agentOutputPath = `${projectPath}/.automaker/features/${featureId}/agent-output.md`;
      delete mockFileSystem[agentOutputPath];
      return { success: true };
    },

    getAgentOutput: async (projectPath: string, featureId: string) => {
      console.log('[Mock] Getting agent output:', { projectPath, featureId });
      const agentOutputPath = `${projectPath}/.automaker/features/${featureId}/agent-output.md`;
      const content = mockFileSystem[agentOutputPath];
      return { success: true, content: content || null };
    },

    generateTitle: async (description: string) => {
      console.log('[Mock] Generating title for:', description.substring(0, 50));
      // Mock title generation - just take first few words
      const words = description.split(/\s+/).slice(0, 6).join(' ');
      const title = words.length > 40 ? words.substring(0, 40) + '...' : words;
      return { success: true, title: `Add ${title}` };
    },
  };
}

// Mock Running Agents API implementation
function createMockRunningAgentsAPI(): RunningAgentsAPI {
  return {
    getAll: async () => {
      console.log('[Mock] Getting all running agents');
      // Return running agents from mock auto mode state
      const runningAgents: RunningAgent[] = Array.from(mockRunningFeatures).map((featureId) => ({
        featureId,
        projectPath: '/mock/project',
        projectName: 'Mock Project',
        isAutoMode: mockAutoModeRunning,
      }));
      return {
        success: true,
        runningAgents,
        totalCount: runningAgents.length,
      };
    },
  };
}

// Mock GitHub API implementation
let mockValidationCallbacks: ((event: IssueValidationEvent) => void)[] = [];

function createMockGitHubAPI(): GitHubAPI {
  return {
    checkRemote: async (projectPath: string) => {
      console.log('[Mock] Checking GitHub remote for:', projectPath);
      return {
        success: true,
        hasGitHubRemote: false,
        remoteUrl: null,
        owner: null,
        repo: null,
      };
    },
    listIssues: async (projectPath: string) => {
      console.log('[Mock] Listing GitHub issues for:', projectPath);
      return {
        success: true,
        openIssues: [],
        closedIssues: [],
      };
    },
    listPRs: async (projectPath: string) => {
      console.log('[Mock] Listing GitHub PRs for:', projectPath);
      return {
        success: true,
        openPRs: [],
        mergedPRs: [],
      };
    },
    validateIssue: async (projectPath: string, issue: IssueValidationInput, model?: AgentModel) => {
      console.log('[Mock] Starting async validation:', { projectPath, issue, model });

      // Simulate async validation in background
      setTimeout(() => {
        mockValidationCallbacks.forEach((cb) =>
          cb({
            type: 'issue_validation_start',
            issueNumber: issue.issueNumber,
            issueTitle: issue.issueTitle,
            projectPath,
          })
        );

        setTimeout(() => {
          mockValidationCallbacks.forEach((cb) =>
            cb({
              type: 'issue_validation_complete',
              issueNumber: issue.issueNumber,
              issueTitle: issue.issueTitle,
              result: {
                verdict: 'valid' as const,
                confidence: 'medium' as const,
                reasoning:
                  'This is a mock validation. In production, Claude SDK would analyze the codebase to validate this issue.',
                relatedFiles: ['src/components/example.tsx'],
                estimatedComplexity: 'moderate' as const,
              },
              projectPath,
              model: model || 'sonnet',
            })
          );
        }, 2000);
      }, 100);

      return {
        success: true,
        message: `Validation started for issue #${issue.issueNumber}`,
        issueNumber: issue.issueNumber,
      };
    },
    getValidationStatus: async (projectPath: string, issueNumber?: number) => {
      console.log('[Mock] Getting validation status:', { projectPath, issueNumber });
      return {
        success: true,
        isRunning: false,
        runningIssues: [],
      };
    },
    stopValidation: async (projectPath: string, issueNumber: number) => {
      console.log('[Mock] Stopping validation:', { projectPath, issueNumber });
      return {
        success: true,
        message: `Validation for issue #${issueNumber} stopped`,
      };
    },
    getValidations: async (projectPath: string, issueNumber?: number) => {
      console.log('[Mock] Getting validations:', { projectPath, issueNumber });
      return {
        success: true,
        validations: [],
      };
    },
    markValidationViewed: async (projectPath: string, issueNumber: number) => {
      console.log('[Mock] Marking validation as viewed:', { projectPath, issueNumber });
      return {
        success: true,
      };
    },
    onValidationEvent: (callback: (event: IssueValidationEvent) => void) => {
      mockValidationCallbacks.push(callback);
      return () => {
        mockValidationCallbacks = mockValidationCallbacks.filter((cb) => cb !== callback);
      };
    },
  };
}

// Utility functions for project management

export interface Project {
  id: string;
  name: string;
  path: string;
  lastOpened?: string;
  theme?: string; // Per-project theme override (uses ThemeMode from app-store)
}

export interface TrashedProject extends Project {
  trashedAt: string;
  deletedFromDisk?: boolean;
}

export const getStoredProjects = (): Project[] => {
  return getJSON<Project[]>(STORAGE_KEYS.PROJECTS) ?? [];
};

export const saveProjects = (projects: Project[]): void => {
  setJSON(STORAGE_KEYS.PROJECTS, projects);
};

export const getCurrentProject = (): Project | null => {
  return getJSON<Project>(STORAGE_KEYS.CURRENT_PROJECT);
};

export const setCurrentProject = (project: Project | null): void => {
  if (project) {
    setJSON(STORAGE_KEYS.CURRENT_PROJECT, project);
  } else {
    removeItem(STORAGE_KEYS.CURRENT_PROJECT);
  }
};

export const addProject = (project: Project): void => {
  const projects = getStoredProjects();
  const existing = projects.findIndex((p) => p.path === project.path);
  if (existing >= 0) {
    projects[existing] = { ...project, lastOpened: new Date().toISOString() };
  } else {
    projects.push({ ...project, lastOpened: new Date().toISOString() });
  }
  saveProjects(projects);
};

export const removeProject = (projectId: string): void => {
  const projects = getStoredProjects().filter((p) => p.id !== projectId);
  saveProjects(projects);
};

export const getStoredTrashedProjects = (): TrashedProject[] => {
  return getJSON<TrashedProject[]>(STORAGE_KEYS.TRASHED_PROJECTS) ?? [];
};

export const saveTrashedProjects = (projects: TrashedProject[]): void => {
  setJSON(STORAGE_KEYS.TRASHED_PROJECTS, projects);
};
