import { useCallback, useEffect, useRef, useState } from 'react';
import { useTheme } from '../../../contexts/ThemeContext';
import { authenticatedFetch } from '../../../utils/api';
import {
  AUTH_STATUS_ENDPOINTS,
  DEFAULT_AUTH_STATUS,
  DEFAULT_CODE_EDITOR_SETTINGS,
  DEFAULT_CURSOR_PERMISSIONS,
} from '../constants/constants';
import type {
  AgentProvider,
  AuthStatus,
  ClaudeMcpFormState,
  ClaudePermissionsState,
  CodeEditorSettingsState,
  CodexMcpFormState,
  CodexPermissionMode,
  CursorPermissionsState,
  GeminiPermissionMode,
  McpServer,
  McpToolsResult,
  McpTestResult,
  NotificationPreferencesState,
  ProjectSortOrder,
  SettingsMainTab,
  SettingsProject,
} from '../types/types';

type ThemeContextValue = {
  isDarkMode: boolean;
  toggleDarkMode: () => void;
};

type UseSettingsControllerArgs = {
  isOpen: boolean;
  initialTab: string;
  projects: SettingsProject[];
  onClose: () => void;
};

type StatusApiResponse = {
  authenticated?: boolean;
  email?: string | null;
  error?: string | null;
  method?: string;
};

type JsonResult = {
  success?: boolean;
  error?: string;
};

type McpReadResponse = {
  success?: boolean;
  servers?: McpServer[];
};

type McpCliServer = {
  name: string;
  type?: string;
  command?: string;
  args?: string[];
  env?: Record<string, string>;
  url?: string;
  headers?: Record<string, string>;
};

type McpCliReadResponse = {
  success?: boolean;
  servers?: McpCliServer[];
};

type McpTestResponse = {
  testResult?: McpTestResult;
  error?: string;
};

type McpToolsResponse = {
  toolsResult?: McpToolsResult;
  error?: string;
};

type ClaudeSettingsStorage = {
  allowedTools?: string[];
  disallowedTools?: string[];
  skipPermissions?: boolean;
  projectSortOrder?: ProjectSortOrder;
};

type CursorSettingsStorage = {
  allowedCommands?: string[];
  disallowedCommands?: string[];
  skipPermissions?: boolean;
};

type CodexSettingsStorage = {
  permissionMode?: CodexPermissionMode;
};

type NotificationPreferencesResponse = {
  success?: boolean;
  preferences?: NotificationPreferencesState;
};

type ActiveLoginProvider = AgentProvider | '';

const KNOWN_MAIN_TABS: SettingsMainTab[] = ['agents', 'appearance', 'git', 'api', 'tasks', 'notifications', 'plugins'];

const normalizeMainTab = (tab: string): SettingsMainTab => {
  // Keep backwards compatibility with older callers that still pass "tools".
  if (tab === 'tools') {
    return 'agents';
  }

  return KNOWN_MAIN_TABS.includes(tab as SettingsMainTab) ? (tab as SettingsMainTab) : 'agents';
};

const getErrorMessage = (error: unknown): string => (
  error instanceof Error ? error.message : 'Unknown error'
);

const parseJson = <T>(value: string | null, fallback: T): T => {
  if (!value) {
    return fallback;
  }

  try {
    return JSON.parse(value) as T;
  } catch {
    return fallback;
  }
};

const toCodexPermissionMode = (value: unknown): CodexPermissionMode => {
  if (value === 'acceptEdits' || value === 'bypassPermissions') {
    return value;
  }

  return 'default';
};

const readCodeEditorSettings = (): CodeEditorSettingsState => ({
  theme: localStorage.getItem('codeEditorTheme') === 'light' ? 'light' : 'dark',
  wordWrap: localStorage.getItem('codeEditorWordWrap') === 'true',
  showMinimap: localStorage.getItem('codeEditorShowMinimap') !== 'false',
  lineNumbers: localStorage.getItem('codeEditorLineNumbers') !== 'false',
  fontSize: localStorage.getItem('codeEditorFontSize') ?? DEFAULT_CODE_EDITOR_SETTINGS.fontSize,
});

const mapCliServersToMcpServers = (servers: McpCliServer[] = []): McpServer[] => (
  servers.map((server) => ({
    id: server.name,
    name: server.name,
    type: server.type || 'stdio',
    scope: 'user',
    config: {
      command: server.command || '',
      args: server.args || [],
      env: server.env || {},
      url: server.url || '',
      headers: server.headers || {},
      timeout: 30000,
    },
    created: new Date().toISOString(),
    updated: new Date().toISOString(),
  }))
);

const getDefaultProject = (projects: SettingsProject[]): SettingsProject => {
  if (projects.length > 0) {
    return projects[0];
  }

  const cwd = typeof process !== 'undefined' && process.cwd ? process.cwd() : '';
  return {
    name: 'default',
    displayName: 'default',
    fullPath: cwd,
    path: cwd,
  };
};

const toResponseJson = async <T>(response: Response): Promise<T> => response.json() as Promise<T>;

const createEmptyClaudePermissions = (): ClaudePermissionsState => ({
  allowedTools: [],
  disallowedTools: [],
  skipPermissions: false,
});

const createEmptyCursorPermissions = (): CursorPermissionsState => ({
  ...DEFAULT_CURSOR_PERMISSIONS,
});

const createDefaultNotificationPreferences = (): NotificationPreferencesState => ({
  channels: {
    inApp: true,
    webPush: false,
  },
  events: {
    actionRequired: true,
    stop: true,
    error: true,
  },
});

export function useSettingsController({ isOpen, initialTab, projects, onClose }: UseSettingsControllerArgs) {
  const { isDarkMode, toggleDarkMode } = useTheme() as ThemeContextValue;
  const closeTimerRef = useRef<number | null>(null);

  const [activeTab, setActiveTab] = useState<SettingsMainTab>(() => normalizeMainTab(initialTab));
  const [saveStatus, setSaveStatus] = useState<'success' | 'error' | null>(null);
  const [deleteError, setDeleteError] = useState<string | null>(null);
  const [projectSortOrder, setProjectSortOrder] = useState<ProjectSortOrder>('name');
  const [codeEditorSettings, setCodeEditorSettings] = useState<CodeEditorSettingsState>(() => (
    readCodeEditorSettings()
  ));

  const [claudePermissions, setClaudePermissions] = useState<ClaudePermissionsState>(() => (
    createEmptyClaudePermissions()
  ));
  const [cursorPermissions, setCursorPermissions] = useState<CursorPermissionsState>(() => (
    createEmptyCursorPermissions()
  ));
  const [notificationPreferences, setNotificationPreferences] = useState<NotificationPreferencesState>(() => (
    createDefaultNotificationPreferences()
  ));
  const [codexPermissionMode, setCodexPermissionMode] = useState<CodexPermissionMode>('default');
  const [geminiPermissionMode, setGeminiPermissionMode] = useState<GeminiPermissionMode>('default');

  const [mcpServers, setMcpServers] = useState<McpServer[]>([]);
  const [cursorMcpServers, setCursorMcpServers] = useState<McpServer[]>([]);
  const [codexMcpServers, setCodexMcpServers] = useState<McpServer[]>([]);
  const [mcpTestResults, setMcpTestResults] = useState<Record<string, McpTestResult>>({});
  const [mcpServerTools, setMcpServerTools] = useState<Record<string, McpToolsResult>>({});
  const [mcpToolsLoading, setMcpToolsLoading] = useState<Record<string, boolean>>({});

  const [showMcpForm, setShowMcpForm] = useState(false);
  const [editingMcpServer, setEditingMcpServer] = useState<McpServer | null>(null);
  const [showCodexMcpForm, setShowCodexMcpForm] = useState(false);
  const [editingCodexMcpServer, setEditingCodexMcpServer] = useState<McpServer | null>(null);

  const [showLoginModal, setShowLoginModal] = useState(false);
  const [loginProvider, setLoginProvider] = useState<ActiveLoginProvider>('');
  const [selectedProject, setSelectedProject] = useState<SettingsProject | null>(null);

  const [claudeAuthStatus, setClaudeAuthStatus] = useState<AuthStatus>(DEFAULT_AUTH_STATUS);
  const [cursorAuthStatus, setCursorAuthStatus] = useState<AuthStatus>(DEFAULT_AUTH_STATUS);
  const [codexAuthStatus, setCodexAuthStatus] = useState<AuthStatus>(DEFAULT_AUTH_STATUS);
  const [geminiAuthStatus, setGeminiAuthStatus] = useState<AuthStatus>(DEFAULT_AUTH_STATUS);

  const setAuthStatusByProvider = useCallback((provider: AgentProvider, status: AuthStatus) => {
    if (provider === 'claude') {
      setClaudeAuthStatus(status);
      return;
    }

    if (provider === 'cursor') {
      setCursorAuthStatus(status);
      return;
    }

    if (provider === 'gemini') {
      setGeminiAuthStatus(status);
      return;
    }

    setCodexAuthStatus(status);
  }, []);

  const checkAuthStatus = useCallback(async (provider: AgentProvider) => {
    try {
      const response = await authenticatedFetch(AUTH_STATUS_ENDPOINTS[provider]);

      if (!response.ok) {
        setAuthStatusByProvider(provider, {
          authenticated: false,
          email: null,
          loading: false,
          error: 'Failed to check authentication status',
        });
        return;
      }

      const data = await toResponseJson<StatusApiResponse>(response);
      setAuthStatusByProvider(provider, {
        authenticated: Boolean(data.authenticated),
        email: data.email || null,
        loading: false,
        error: data.error || null,
        method: data.method,
      });
    } catch (error) {
      console.error(`Error checking ${provider} auth status:`, error);
      setAuthStatusByProvider(provider, {
        authenticated: false,
        email: null,
        loading: false,
        error: getErrorMessage(error),
      });
    }
  }, [setAuthStatusByProvider]);

  const fetchCursorMcpServers = useCallback(async () => {
    try {
      const response = await authenticatedFetch('/api/cursor/mcp');
      if (!response.ok) {
        console.error('Failed to fetch Cursor MCP servers');
        return;
      }

      const data = await toResponseJson<{ servers?: McpServer[] }>(response);
      setCursorMcpServers(data.servers || []);
    } catch (error) {
      console.error('Error fetching Cursor MCP servers:', error);
    }
  }, []);

  const fetchCodexMcpServers = useCallback(async () => {
    try {
      const configResponse = await authenticatedFetch('/api/codex/mcp/config/read');

      if (configResponse.ok) {
        const configData = await toResponseJson<McpReadResponse>(configResponse);
        if (configData.success && configData.servers) {
          setCodexMcpServers(configData.servers);
          return;
        }
      }

      const cliResponse = await authenticatedFetch('/api/codex/mcp/cli/list');
      if (!cliResponse.ok) {
        return;
      }

      const cliData = await toResponseJson<McpCliReadResponse>(cliResponse);
      if (!cliData.success || !cliData.servers) {
        return;
      }

      setCodexMcpServers(mapCliServersToMcpServers(cliData.servers));
    } catch (error) {
      console.error('Error fetching Codex MCP servers:', error);
    }
  }, []);

  const fetchMcpServers = useCallback(async () => {
    try {
      const configResponse = await authenticatedFetch('/api/mcp/config/read');
      if (configResponse.ok) {
        const configData = await toResponseJson<McpReadResponse>(configResponse);
        if (configData.success && configData.servers) {
          setMcpServers(configData.servers);
          return;
        }
      }

      const cliResponse = await authenticatedFetch('/api/mcp/cli/list');
      if (cliResponse.ok) {
        const cliData = await toResponseJson<McpCliReadResponse>(cliResponse);
        if (cliData.success && cliData.servers) {
          setMcpServers(mapCliServersToMcpServers(cliData.servers));
          return;
        }
      }

      const fallbackResponse = await authenticatedFetch('/api/mcp/servers?scope=user');
      if (!fallbackResponse.ok) {
        console.error('Failed to fetch MCP servers');
        return;
      }

      const fallbackData = await toResponseJson<{ servers?: McpServer[] }>(fallbackResponse);
      setMcpServers(fallbackData.servers || []);
    } catch (error) {
      console.error('Error fetching MCP servers:', error);
    }
  }, []);

  const deleteMcpServer = useCallback(async (serverId: string, scope = 'user') => {
    const response = await authenticatedFetch(`/api/mcp/cli/remove/${serverId}?scope=${scope}`, {
      method: 'DELETE',
    });

    if (!response.ok) {
      const error = await toResponseJson<JsonResult>(response);
      throw new Error(error.error || 'Failed to delete server');
    }

    const result = await toResponseJson<JsonResult>(response);
    if (!result.success) {
      throw new Error(result.error || 'Failed to delete server via Claude CLI');
    }
  }, []);

  const saveMcpServer = useCallback(
    async (serverData: ClaudeMcpFormState, editingServer: McpServer | null) => {
      const newServerScope = serverData.scope || 'user';

      const response = await authenticatedFetch('/api/mcp/cli/add', {
        method: 'POST',
        body: JSON.stringify({
          name: serverData.name,
          type: serverData.type,
          scope: newServerScope,
          projectPath: serverData.projectPath,
          command: serverData.config.command,
          args: serverData.config.args || [],
          url: serverData.config.url,
          headers: serverData.config.headers || {},
          env: serverData.config.env || {},
        }),
      });

      if (!response.ok) {
        const error = await toResponseJson<JsonResult>(response);
        throw new Error(error.error || 'Failed to save server');
      }

      const result = await toResponseJson<JsonResult>(response);
      if (!result.success) {
        throw new Error(result.error || 'Failed to save server via Claude CLI');
      }

      if (!editingServer?.id) {
        return;
      }

      const previousServerScope = editingServer.scope || 'user';
      const didServerIdentityChange =
        editingServer.id !== serverData.name || previousServerScope !== newServerScope;

      if (!didServerIdentityChange) {
        return;
      }

      try {
        await deleteMcpServer(editingServer.id, previousServerScope);
      } catch (error) {
        console.warn('Saved MCP server update but failed to remove the previous server entry.', {
          previousServerId: editingServer.id,
          previousServerScope,
          error: getErrorMessage(error),
        });
      }
    },
    [deleteMcpServer],
  );

  const submitMcpForm = useCallback(
    async (formData: ClaudeMcpFormState, editingServer: McpServer | null) => {
      if (formData.importMode === 'json') {
        const response = await authenticatedFetch('/api/mcp/cli/add-json', {
          method: 'POST',
          body: JSON.stringify({
            name: formData.name,
            jsonConfig: formData.jsonInput,
            scope: formData.scope,
            projectPath: formData.projectPath,
          }),
        });

        if (!response.ok) {
          const error = await toResponseJson<JsonResult>(response);
          throw new Error(error.error || 'Failed to add server');
        }

        const result = await toResponseJson<JsonResult>(response);
        if (!result.success) {
          throw new Error(result.error || 'Failed to add server via JSON');
        }
      } else {
        await saveMcpServer(formData, editingServer);
      }

      await fetchMcpServers();
      setSaveStatus('success');
      setShowMcpForm(false);
      setEditingMcpServer(null);
    },
    [fetchMcpServers, saveMcpServer],
  );

  const handleMcpDelete = useCallback(
    async (serverId: string, scope = 'user') => {
      if (!window.confirm('Are you sure you want to delete this MCP server?')) {
        return;
      }

      setDeleteError(null);
      try {
        await deleteMcpServer(serverId, scope);
        await fetchMcpServers();
        setDeleteError(null);
        setSaveStatus('success');
      } catch (error) {
        setDeleteError(getErrorMessage(error));
        setSaveStatus('error');
      }
    },
    [deleteMcpServer, fetchMcpServers],
  );

  const testMcpServer = useCallback(async (serverId: string, scope = 'user') => {
    const response = await authenticatedFetch(`/api/mcp/servers/${serverId}/test?scope=${scope}`, {
      method: 'POST',
    });

    if (!response.ok) {
      const error = await toResponseJson<McpTestResponse>(response);
      throw new Error(error.error || 'Failed to test server');
    }

    const data = await toResponseJson<McpTestResponse>(response);
    return data.testResult || { success: false, message: 'No test result returned' };
  }, []);

  const discoverMcpTools = useCallback(async (serverId: string, scope = 'user') => {
    const response = await authenticatedFetch(`/api/mcp/servers/${serverId}/tools?scope=${scope}`, {
      method: 'POST',
    });

    if (!response.ok) {
      const error = await toResponseJson<McpToolsResponse>(response);
      throw new Error(error.error || 'Failed to discover tools');
    }

    const data = await toResponseJson<McpToolsResponse>(response);
    return data.toolsResult || { success: false, tools: [], resources: [], prompts: [] };
  }, []);

  const handleMcpTest = useCallback(
    async (serverId: string, scope = 'user') => {
      try {
        setMcpTestResults((prev) => ({
          ...prev,
          [serverId]: { success: false, message: 'Testing server...', details: [], loading: true },
        }));

        const result = await testMcpServer(serverId, scope);
        setMcpTestResults((prev) => ({ ...prev, [serverId]: result }));
      } catch (error) {
        setMcpTestResults((prev) => ({
          ...prev,
          [serverId]: {
            success: false,
            message: getErrorMessage(error),
            details: [],
          },
        }));
      }
    },
    [testMcpServer],
  );

  const handleMcpToolsDiscovery = useCallback(
    async (serverId: string, scope = 'user') => {
      try {
        setMcpToolsLoading((prev) => ({ ...prev, [serverId]: true }));
        const result = await discoverMcpTools(serverId, scope);
        setMcpServerTools((prev) => ({ ...prev, [serverId]: result }));
      } catch {
        setMcpServerTools((prev) => ({
          ...prev,
          [serverId]: { success: false, tools: [], resources: [], prompts: [] },
        }));
      } finally {
        setMcpToolsLoading((prev) => ({ ...prev, [serverId]: false }));
      }
    },
    [discoverMcpTools],
  );

  const deleteCodexMcpServer = useCallback(async (serverId: string) => {
    const response = await authenticatedFetch(`/api/codex/mcp/cli/remove/${serverId}`, {
      method: 'DELETE',
    });

    if (!response.ok) {
      const error = await toResponseJson<JsonResult>(response);
      throw new Error(error.error || 'Failed to delete server');
    }

    const result = await toResponseJson<JsonResult>(response);
    if (!result.success) {
      throw new Error(result.error || 'Failed to delete Codex MCP server');
    }
  }, []);

  const saveCodexMcpServer = useCallback(
    async (serverData: CodexMcpFormState, editingServer: McpServer | null) => {
      const response = await authenticatedFetch('/api/codex/mcp/cli/add', {
        method: 'POST',
        body: JSON.stringify({
          name: serverData.name,
          command: serverData.config.command,
          args: serverData.config.args || [],
          env: serverData.config.env || {},
        }),
      });

      if (!response.ok) {
        const error = await toResponseJson<JsonResult>(response);
        throw new Error(error.error || 'Failed to save server');
      }

      const result = await toResponseJson<JsonResult>(response);
      if (!result.success) {
        throw new Error(result.error || 'Failed to save Codex MCP server');
      }

      if (!editingServer?.name || editingServer.name === serverData.name) {
        return;
      }

      try {
        await deleteCodexMcpServer(editingServer.name);
      } catch (error) {
        console.warn('Saved Codex MCP server update but failed to remove the previous server entry.', {
          previousServerName: editingServer.name,
          error: getErrorMessage(error),
        });
      }
    },
    [deleteCodexMcpServer],
  );

  const submitCodexMcpForm = useCallback(
    async (formData: CodexMcpFormState, editingServer: McpServer | null) => {
      await saveCodexMcpServer(formData, editingServer);
      await fetchCodexMcpServers();
      setSaveStatus('success');
      setShowCodexMcpForm(false);
      setEditingCodexMcpServer(null);
    },
    [fetchCodexMcpServers, saveCodexMcpServer],
  );

  const handleCodexMcpDelete = useCallback(
    async (serverName: string) => {
      if (!window.confirm('Are you sure you want to delete this MCP server?')) {
        return;
      }

      setDeleteError(null);
      try {
        await deleteCodexMcpServer(serverName);
        await fetchCodexMcpServers();
        setDeleteError(null);
        setSaveStatus('success');
      } catch (error) {
        setDeleteError(getErrorMessage(error));
        setSaveStatus('error');
      }
    },
    [deleteCodexMcpServer, fetchCodexMcpServers],
  );

  const loadSettings = useCallback(async () => {
    try {
      const savedClaudeSettings = parseJson<ClaudeSettingsStorage>(
        localStorage.getItem('claude-settings'),
        {},
      );
      setClaudePermissions({
        allowedTools: savedClaudeSettings.allowedTools || [],
        disallowedTools: savedClaudeSettings.disallowedTools || [],
        skipPermissions: Boolean(savedClaudeSettings.skipPermissions),
      });
      setProjectSortOrder(savedClaudeSettings.projectSortOrder === 'date' ? 'date' : 'name');

      const savedCursorSettings = parseJson<CursorSettingsStorage>(
        localStorage.getItem('cursor-tools-settings'),
        {},
      );
      setCursorPermissions({
        allowedCommands: savedCursorSettings.allowedCommands || [],
        disallowedCommands: savedCursorSettings.disallowedCommands || [],
        skipPermissions: Boolean(savedCursorSettings.skipPermissions),
      });

      const savedCodexSettings = parseJson<CodexSettingsStorage>(
        localStorage.getItem('codex-settings'),
        {},
      );
      setCodexPermissionMode(toCodexPermissionMode(savedCodexSettings.permissionMode));

      const savedGeminiSettings = parseJson<{ permissionMode?: GeminiPermissionMode }>(
        localStorage.getItem('gemini-settings'),
        {},
      );
      setGeminiPermissionMode(savedGeminiSettings.permissionMode || 'default');

      try {
        const notificationResponse = await authenticatedFetch('/api/settings/notification-preferences');
        if (notificationResponse.ok) {
          const notificationData = await toResponseJson<NotificationPreferencesResponse>(notificationResponse);
          if (notificationData.success && notificationData.preferences) {
            setNotificationPreferences(notificationData.preferences);
          } else {
            setNotificationPreferences(createDefaultNotificationPreferences());
          }
        } else {
          setNotificationPreferences(createDefaultNotificationPreferences());
        }
      } catch {
        setNotificationPreferences(createDefaultNotificationPreferences());
      }

      await Promise.all([
        fetchMcpServers(),
        fetchCursorMcpServers(),
        fetchCodexMcpServers(),
      ]);
    } catch (error) {
      console.error('Error loading settings:', error);
      setClaudePermissions(createEmptyClaudePermissions());
      setCursorPermissions(createEmptyCursorPermissions());
      setNotificationPreferences(createDefaultNotificationPreferences());
      setCodexPermissionMode('default');
      setProjectSortOrder('name');
    }
  }, [fetchCodexMcpServers, fetchCursorMcpServers, fetchMcpServers]);

  const openLoginForProvider = useCallback((provider: AgentProvider) => {
    setLoginProvider(provider);
    setSelectedProject(getDefaultProject(projects));
    setShowLoginModal(true);
  }, [projects]);

  const handleLoginComplete = useCallback((exitCode: number) => {
    if (exitCode !== 0 || !loginProvider) {
      return;
    }

    setSaveStatus('success');
    void checkAuthStatus(loginProvider);
  }, [checkAuthStatus, loginProvider]);

  const saveSettings = useCallback(async () => {
    setSaveStatus(null);

    try {
      const now = new Date().toISOString();
      localStorage.setItem('claude-settings', JSON.stringify({
        allowedTools: claudePermissions.allowedTools,
        disallowedTools: claudePermissions.disallowedTools,
        skipPermissions: claudePermissions.skipPermissions,
        projectSortOrder,
        lastUpdated: now,
      }));

      localStorage.setItem('cursor-tools-settings', JSON.stringify({
        allowedCommands: cursorPermissions.allowedCommands,
        disallowedCommands: cursorPermissions.disallowedCommands,
        skipPermissions: cursorPermissions.skipPermissions,
        lastUpdated: now,
      }));

      localStorage.setItem('codex-settings', JSON.stringify({
        permissionMode: codexPermissionMode,
        lastUpdated: now,
      }));

      localStorage.setItem('gemini-settings', JSON.stringify({
        permissionMode: geminiPermissionMode,
        lastUpdated: now,
      }));

      const notificationResponse = await authenticatedFetch('/api/settings/notification-preferences', {
        method: 'PUT',
        body: JSON.stringify(notificationPreferences),
      });
      if (!notificationResponse.ok) {
        throw new Error('Failed to save notification preferences');
      }

      setSaveStatus('success');
    } catch (error) {
      console.error('Error saving settings:', error);
      setSaveStatus('error');
    }
  }, [
    claudePermissions.allowedTools,
    claudePermissions.disallowedTools,
    claudePermissions.skipPermissions,
    codexPermissionMode,
    cursorPermissions.allowedCommands,
    cursorPermissions.disallowedCommands,
    cursorPermissions.skipPermissions,
    notificationPreferences,
    geminiPermissionMode,
    projectSortOrder,
  ]);

  const updateCodeEditorSetting = useCallback(
    <K extends keyof CodeEditorSettingsState>(key: K, value: CodeEditorSettingsState[K]) => {
      setCodeEditorSettings((prev) => ({ ...prev, [key]: value }));
    },
    [],
  );

  const openMcpForm = useCallback((server?: McpServer) => {
    setEditingMcpServer(server || null);
    setShowMcpForm(true);
  }, []);

  const closeMcpForm = useCallback(() => {
    setShowMcpForm(false);
    setEditingMcpServer(null);
  }, []);

  const openCodexMcpForm = useCallback((server?: McpServer) => {
    setEditingCodexMcpServer(server || null);
    setShowCodexMcpForm(true);
  }, []);

  const closeCodexMcpForm = useCallback(() => {
    setShowCodexMcpForm(false);
    setEditingCodexMcpServer(null);
  }, []);

  useEffect(() => {
    if (!isOpen) {
      return;
    }

    setActiveTab(normalizeMainTab(initialTab));
    void loadSettings();
    void checkAuthStatus('claude');
    void checkAuthStatus('cursor');
    void checkAuthStatus('codex');
    void checkAuthStatus('gemini');
  }, [checkAuthStatus, initialTab, isOpen, loadSettings]);

  useEffect(() => {
    localStorage.setItem('codeEditorTheme', codeEditorSettings.theme);
    localStorage.setItem('codeEditorWordWrap', String(codeEditorSettings.wordWrap));
    localStorage.setItem('codeEditorShowMinimap', String(codeEditorSettings.showMinimap));
    localStorage.setItem('codeEditorLineNumbers', String(codeEditorSettings.lineNumbers));
    localStorage.setItem('codeEditorFontSize', codeEditorSettings.fontSize);
    window.dispatchEvent(new Event('codeEditorSettingsChanged'));
  }, [codeEditorSettings]);

  // Auto-save permissions and sort order with debounce
  const autoSaveTimerRef = useRef<number | null>(null);
  const isInitialLoadRef = useRef(true);

  useEffect(() => {
    // Skip auto-save on initial load (settings are being loaded from localStorage)
    if (isInitialLoadRef.current) {
      isInitialLoadRef.current = false;
      return;
    }

    if (autoSaveTimerRef.current !== null) {
      window.clearTimeout(autoSaveTimerRef.current);
    }

    autoSaveTimerRef.current = window.setTimeout(() => {
      saveSettings();
    }, 500);

    return () => {
      if (autoSaveTimerRef.current !== null) {
        window.clearTimeout(autoSaveTimerRef.current);
      }
    };
  }, [saveSettings]);

  // Clear save status after 2 seconds
  useEffect(() => {
    if (saveStatus === null) {
      return;
    }

    const timer = window.setTimeout(() => setSaveStatus(null), 2000);
    return () => window.clearTimeout(timer);
  }, [saveStatus]);

  // Reset initial load flag when settings dialog opens
  useEffect(() => {
    if (isOpen) {
      isInitialLoadRef.current = true;
    }
  }, [isOpen]);

  useEffect(() => () => {
    if (closeTimerRef.current !== null) {
      window.clearTimeout(closeTimerRef.current);
      closeTimerRef.current = null;
    }
    if (autoSaveTimerRef.current !== null) {
      window.clearTimeout(autoSaveTimerRef.current);
      autoSaveTimerRef.current = null;
    }
  }, []);

  return {
    activeTab,
    setActiveTab,
    isDarkMode,
    toggleDarkMode,
    saveStatus,
    deleteError,
    projectSortOrder,
    setProjectSortOrder,
    codeEditorSettings,
    updateCodeEditorSetting,
    claudePermissions,
    setClaudePermissions,
    cursorPermissions,
    setCursorPermissions,
    notificationPreferences,
    setNotificationPreferences,
    codexPermissionMode,
    setCodexPermissionMode,
    mcpServers,
    cursorMcpServers,
    codexMcpServers,
    mcpTestResults,
    mcpServerTools,
    mcpToolsLoading,
    showMcpForm,
    editingMcpServer,
    openMcpForm,
    closeMcpForm,
    submitMcpForm,
    handleMcpDelete,
    handleMcpTest,
    handleMcpToolsDiscovery,
    showCodexMcpForm,
    editingCodexMcpServer,
    openCodexMcpForm,
    closeCodexMcpForm,
    submitCodexMcpForm,
    handleCodexMcpDelete,
    claudeAuthStatus,
    cursorAuthStatus,
    codexAuthStatus,
    geminiAuthStatus,
    geminiPermissionMode,
    setGeminiPermissionMode,
    openLoginForProvider,
    showLoginModal,
    setShowLoginModal,
    loginProvider,
    selectedProject,
    handleLoginComplete,
  };
}
