• Settings page component for the Kenmei to AniList sync tool.

    Handles authentication, sync preferences, data management, and cache clearing for the user.

    Returns Element

    export function SettingsPage() {
    // All settings section IDs that can be collapsed
    const SECTION_IDS = [
    "matching-preferences",
    "sync-preferences",
    "data-management",
    "backup-restore",
    "debug-tools",
    "update-management",
    ] as const;

    const {
    authState,
    isLoading,
    error: authError,
    statusMessage,
    customCredentials,
    } = useAuthState();

    const {
    login,
    refreshToken,
    logout,
    cancelAuth,
    setCredentialSource,
    updateCustomCredentials,
    } = useAuthActions();

    const {
    isDebugEnabled,
    isStorageDebuggerEnabled,
    isLogViewerEnabled,
    isLogRedactionEnabled,
    isStateInspectorEnabled,
    isIpcViewerEnabled,
    isEventLoggerEnabled,
    isConfidenceTestExporterEnabled,
    isPerformanceMonitorEnabled,
    } = useDebugState();

    const {
    toggleDebug,
    setIsStorageDebuggerEnabled,
    setIsLogViewerEnabled,
    setIsLogRedactionEnabled,
    setIsStateInspectorEnabled,
    setIsIpcViewerEnabled,
    setIsEventLoggerEnabled,
    setIsConfidenceTestExporterEnabled,
    setIsPerformanceMonitorEnabled,
    recordEvent,
    } = useDebugActions();

    const { completeStep, isActive } = useOnboarding();

    // Auto-updater hook for managing download/install operations
    const { isDownloading, downloadProgress, isDownloaded } = useAutoUpdater();

    const prevCredentialSourceRef = useRef<"default" | "custom">(
    authState.credentialSource,
    );

    const [error, setError] = useState<AppError | null>(null);
    const [isCacheCleared, setIsCacheCleared] = useState(false);
    const [isClearing, setIsClearing] = useState(false);
    const [showStatusMessage, setShowStatusMessage] = useState(true);
    const [cachesToClear, setCachesToClear] = useState<CachesToClear>({
    shouldClearAuthCache: false,
    shouldClearSettingsCache: false,
    shouldClearSyncCache: false,
    shouldClearImportCache: false,
    shouldClearReviewCache: false,
    shouldClearMangaCache: false,
    shouldClearSearchCache: false,
    shouldClearOtherCache: false,
    });
    const [isUsingCustomCredentials, setIsUsingCustomCredentials] = useState(
    authState.credentialSource === "custom",
    );
    const [clientId, setClientId] = useState("");
    const [clientSecret, setClientSecret] = useState("");
    const [redirectUri, setRedirectUri] = useState(
    `http://localhost:${DEFAULT_AUTH_PORT}/callback`,
    );
    const [syncConfig, setSyncConfig] = useState<SyncConfig>(getSyncConfig());
    const [matchConfig, setMatchConfig] = useState<MatchConfig>(getMatchConfig());
    const [isCustomThresholdEnabled, setIsCustomThresholdEnabled] =
    useState<boolean>(
    typeof syncConfig.autoPauseThreshold === "string" ||
    ![1, 7, 14, 30, 60, 90, 180, 365].includes(
    Number(syncConfig.autoPauseThreshold),
    ),
    );
    // Update Check State
    const [updateChannel, setUpdateChannel] = useState<"stable" | "beta">(
    "stable",
    );
    const [isCheckingUpdate, setIsCheckingUpdate] = useState(false);
    const [updateInfo, setUpdateInfo] = useState<null | {
    version: string;
    url: string;
    isBeta: boolean;
    }>(null);
    const [updateError, setUpdateError] = useState<string | null>(null);

    // Backup management state
    const [isRestoringBackup, setIsRestoringBackup] = useState(false);
    const [selectedBackupFile, setSelectedBackupFile] = useState<File | null>(
    null,
    );
    const [backupValidationError, setBackupValidationError] = useState<
    string | null
    >(null);

    // Backup schedule state
    const [scheduleConfig, setScheduleConfig] = useState<BackupScheduleConfig>(
    DEFAULT_BACKUP_SCHEDULE_CONFIG,
    );
    const [nextScheduledBackup, setNextScheduledBackup] = useState<number | null>(
    null,
    );
    const [lastScheduledBackup, setLastScheduledBackup] = useState<number | null>(
    null,
    );
    const [isTriggeringBackup, setIsTriggeringBackup] = useState(false);

    // Settings search state
    const [searchQuery, setSearchQuery] = useState<string>("");
    const [searchResults, setSearchResults] = useState<SettingsSearchResult[]>(
    [],
    );
    const [highlightedSectionId, setHighlightedSectionId] = useState<
    string | null
    >(null);
    const searchInputRef = useRef<HTMLInputElement>(null);

    // Collapsed sections state
    const [collapsedSections, setCollapsedSections] = useState<
    Record<string, boolean>
    >({});

    /**
    * Saves sync configuration with debug event logging.
    * @param config - Updated sync configuration to save.
    * @param changedField - The name of the configuration field that changed.
    * @source
    */
    const saveSyncConfigWithEvent = (
    config: SyncConfig,
    changedField: string,
    ) => {
    recordEvent({
    type: "settings.sync-config-update",
    message: `Sync config updated: ${changedField}`,
    level: "info",
    metadata: { changedField, config },
    });
    saveSyncConfig(config);
    };

    /**
    * Saves match configuration with debug event logging.
    * @param config - Updated match configuration to save.
    * @param changedField - The name of the configuration field that changed.
    * @source
    */
    const saveMatchConfigWithEvent = (
    config: MatchConfig,
    changedField: string,
    ) => {
    recordEvent({
    type: "settings.match-config-update",
    message: `Match config updated: ${changedField}`,
    level: "info",
    metadata: { changedField, config },
    });
    saveMatchConfig(config);
    setMatchConfig(config);
    };

    /**
    * Opens an external URL in the default browser or system default application.
    * Prefers Electron API if available, otherwise falls back to standard browser open.
    * @param url - The URL to open.
    * @returns A React event handler function.
    * @source
    */
    const handleOpenExternal =
    (url: string) => async (e: React.SyntheticEvent) => {
    e.preventDefault();
    const res = await openExternalSafe(url);
    if (!res.success) {
    console.error("[Settings] Failed to open external URL:", res.error);
    }
    };

    // Create searchable settings sections index
    const settingsSections = useMemo<SettingsSection[]>(() => {
    type SectionDef = Omit<SettingsSection, "tab">;

    const grouped: Record<string, SectionDef[]> = {
    matching: [
    {
    id: "matching-one-shots",
    title: "Ignore one shots in automatic matching",
    description: "Skip one-shot manga during automatic matching",
    keywords: ["skip", "filter", "one-shot", "exclude"],
    },
    {
    id: "matching-adult-content",
    title: "Ignore adult content in automatic matching",
    description: "Skip adult content manga during automatic matching",
    keywords: ["nsfw", "adult", "18+", "filter", "ignore"],
    },
    {
    id: "matching-blur-adult",
    title: "Blur adult content images",
    description: "Blur cover images marked as adult content",
    keywords: ["privacy", "nsfw", "blur", "hide", "censor"],
    },
    {
    id: "matching-comick",
    title: "Enable Comick alternative search",
    description: "Use Comick as a fallback search source",
    keywords: ["fallback", "alternative", "source", "comick"],
    },
    {
    id: "matching-mangadex",
    title: "Enable MangaDex alternative search",
    description: "Use MangaDex as a fallback search source",
    keywords: ["fallback", "alternative", "source", "mangadex"],
    },
    {
    id: "matching-extra-searches",
    title: "Enable extra title searches",
    description:
    "Perform additional searches using parts of the title (e.g. subtitle)",
    keywords: ["extra", "search", "subtitle", "punctuation", "fuzzy"],
    },
    {
    id: "matching-custom-rules",
    title: "Custom Matching Rules",
    description:
    "Define regex patterns to automatically skip or accept manga",
    keywords: ["advanced", "regex", "filter", "pattern", "custom"],
    },
    ],
    sync: [
    {
    id: "sync-auto-pause",
    title: "Auto-pause inactive manga",
    description:
    "Automatically pause and pause sync for manga not updated within the threshold period",
    keywords: [
    "inactive",
    "pause",
    "automatic",
    "timeout",
    "threshold",
    "sync",
    ],
    },
    {
    id: "sync-status-priority",
    title: "Status priority toggles",
    description:
    "Control which source takes priority: AniList or Kenmei data during sync",
    keywords: [
    "reading",
    "completed",
    "dropped",
    "priority",
    "status",
    "anilist",
    "kenmei",
    "source",
    ],
    },
    {
    id: "sync-privacy",
    title: "Privacy settings",
    description:
    "Set AniList entries as private to control visibility and sharing of your synced manga",
    keywords: [
    "private",
    "public",
    "visibility",
    "privacy",
    "sharing",
    "anilist",
    ],
    },
    ],
    data: [
    {
    id: "data-cache",
    title: "Cache Management",
    description:
    "Select which cached data types to clear and reset. Cache types include authentication, settings, sync, and more",
    keywords: [
    "clear",
    "reset",
    "storage",
    "cache",
    "authentication",
    "settings",
    "sync",
    "manga",
    "search",
    "temp",
    ],
    },
    {
    id: "data-backup",
    title: "Backup & Restore",
    description:
    "Export and save all Kenmei data as backups, or import and restore from previously created backup files",
    keywords: [
    "export",
    "import",
    "backup",
    "restore",
    "save",
    "download",
    "upload",
    "history",
    ],
    },
    {
    id: "data-debug",
    title: "Debug Tools",
    description:
    "Enable debug features including logs, logger, storage inspection, state inspection, IPC monitoring, and confidence testing",
    keywords: [
    "developer",
    "debug",
    "logs",
    "logger",
    "tools",
    "storage",
    "state",
    "ipc",
    "confidence",
    "test",
    "redact",
    "event",
    ],
    },
    ],
    };

    return Object.entries(grouped).flatMap(([tab, items]) =>
    items.map((it) => ({ ...it, tab: tab as SettingsSection["tab"] })),
    );
    }, []);

    // Initialize Fuse.js for fuzzy search
    const fuse = useMemo(() => {
    return new Fuse<SettingsSection>(settingsSections, {
    keys: [
    { name: "title", weight: 0.3 },
    { name: "description", weight: 0.5 },
    { name: "keywords", weight: 0.2 },
    ],
    threshold: 0.2,
    includeScore: true,
    includeMatches: true,
    minMatchCharLength: 3,
    ignoreLocation: true,
    });
    }, [settingsSections]);

    /**
    * Performs fuzzy search on settings sections using Fuse.js.
    * @param query - Search query string.
    * @returns Array of settings search results with scores and matches.
    * @source
    */
    const performSearch = useCallback(
    (query: string): SettingsSearchResult[] => {
    if (!query.trim()) {
    return [];
    }
    const results: FuseResult<SettingsSection>[] = fuse.search(query);
    console.log("[Settings] Search results for query:", query, results);
    return results.map((result) => ({
    section: result.item,
    score: result.score || 0,
    matches: result.matches ? Array.from(result.matches) : [],
    }));
    },
    [fuse],
    );

    /**
    * Handles search query input changes and updates search results.
    * @param value - The new search query value.
    * @source
    */
    const handleSearchChange = useCallback(
    (value: string) => {
    setSearchQuery(value);
    sessionStorage.setItem("settings-search-query", value);

    // Update search results
    if (value.trim()) {
    const results = performSearch(value);
    setSearchResults(results);
    } else {
    setSearchResults([]);
    setHighlightedSectionId(null);
    }
    },
    [performSearch],
    );

    // Load search query from session on mount
    useEffect(() => {
    const savedQuery = sessionStorage.getItem("settings-search-query");
    if (savedQuery) {
    setSearchQuery(savedQuery);
    // Perform search with saved query
    const results = fuse.search(savedQuery).map(
    (result) =>
    ({
    section: result.item,
    score: result.score || 0,
    matches: result.matches || [],
    }) as SettingsSearchResult,
    );
    if (results.length > 0) {
    setSearchResults(results);
    }
    }
    }, []);

    // Keyboard shortcut handler for Ctrl+F (Windows/Linux) and Cmd+F (macOS)
    useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
    if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "f") {
    e.preventDefault();
    searchInputRef.current?.focus();
    searchInputRef.current?.select();
    }
    };

    globalThis.addEventListener("keydown", handleKeyDown);
    return () => globalThis.removeEventListener("keydown", handleKeyDown);
    }, []);

    // Track previous credential values to prevent unnecessary updates
    const prevCredentialsRef = useRef({
    id: "",
    secret: "",
    uri: "",
    });

    // Update error state when auth error changes
    useEffect(() => {
    if (authError) {
    setError(createError(ErrorType.AUTH, authError));
    } else {
    setError(null);
    }
    }, [authError]);

    // Update credential source when toggle changes, but avoid infinite loop
    useEffect(() => {
    const newSource = isUsingCustomCredentials ? "custom" : "default";
    // Only update if actually changed and not from authState sync
    if (newSource !== prevCredentialSourceRef.current) {
    prevCredentialSourceRef.current = newSource;
    setCredentialSource(newSource);
    }
    }, [isUsingCustomCredentials, setCredentialSource]);

    // Update local state if authState.credentialSource changes externally
    useEffect(() => {
    if (authState.credentialSource !== prevCredentialSourceRef.current) {
    prevCredentialSourceRef.current = authState.credentialSource;
    setIsUsingCustomCredentials(authState.credentialSource === "custom");
    }
    }, [authState.credentialSource]);

    // Update custom credentials when fields change
    useEffect(() => {
    if (isUsingCustomCredentials && clientId && clientSecret && redirectUri) {
    // Only update if values actually changed
    if (
    clientId !== prevCredentialsRef.current.id ||
    clientSecret !== prevCredentialsRef.current.secret ||
    redirectUri !== prevCredentialsRef.current.uri
    ) {
    // Update the ref
    prevCredentialsRef.current = {
    id: clientId,
    secret: clientSecret,
    uri: redirectUri,
    };

    // Update context
    updateCustomCredentials(clientId, clientSecret, redirectUri);
    }
    }
    }, [
    isUsingCustomCredentials,
    clientId,
    clientSecret,
    redirectUri,
    updateCustomCredentials,
    ]);

    // Reset error when auth state changes
    useEffect(() => {
    if (authState.isAuthenticated) {
    setError(null);

    // If we have a status message and authentication is complete,
    // set a timeout to clear the status message
    if (statusMessage && !isLoading) {
    const timer = setTimeout(() => {
    setShowStatusMessage(false);
    }, 3000); // Auto-dismiss after 3 seconds

    return () => clearTimeout(timer);
    }
    } else {
    // Reset the status message visibility when not authenticated
    setShowStatusMessage(true);
    }
    }, [authState.isAuthenticated, statusMessage, isLoading]);

    // Track auth completion for onboarding
    useEffect(() => {
    if (isActive && authState.isAuthenticated && !isLoading) {
    completeStep("auth");
    }
    }, [authState.isAuthenticated, isActive, isLoading, completeStep]);

    // Add a timeout to detect stuck loading state
    useEffect(() => {
    let timeoutId: NodeJS.Timeout | null = null;

    if (isLoading) {
    // If loading state persists for more than 20 seconds, trigger a refresh
    timeoutId = setTimeout(() => {
    console.warn(
    "[Settings] Loading state persisted for too long - triggering refresh",
    );
    handleRefreshPage();
    }, 20000);
    }

    return () => {
    if (timeoutId) clearTimeout(timeoutId);
    };
    }, [isLoading]);

    // Add a useEffect to load custom credential settings from localStorage on initial mount
    useEffect(() => {
    try {
    console.debug("[Settings] 🔍 Loading custom credential settings...");

    // Load custom credentials toggle state
    const savedUseCustom = localStorage.getItem("useCustomCredentials");
    if (savedUseCustom) {
    setIsUsingCustomCredentials(JSON.parse(savedUseCustom));
    console.debug(
    `[Settings] 🔍 Custom credentials enabled: ${savedUseCustom}`,
    );
    }

    // Load saved custom credentials if they exist
    const savedCustomCreds = localStorage.getItem("customCredentials");
    if (savedCustomCreds) {
    const credentials = JSON.parse(savedCustomCreds);
    setClientId(credentials.clientId || "");
    setClientSecret(credentials.clientSecret || "");
    setRedirectUri(
    credentials.redirectUri ||
    `http://localhost:${DEFAULT_AUTH_PORT}/callback`,
    );

    console.info("[Settings] ✅ Loaded custom credentials from storage");

    // Also update context with saved credentials
    if (
    credentials.clientId &&
    credentials.clientSecret &&
    credentials.redirectUri
    ) {
    updateCustomCredentials(
    credentials.clientId,
    credentials.clientSecret,
    credentials.redirectUri,
    );
    }
    }
    } catch (err) {
    console.error(
    "[Settings] ❌ Failed to load saved credential settings:",
    err,
    );
    }
    }, []);

    // Save custom credentials toggle state whenever it changes
    useEffect(() => {
    console.debug(
    `[Settings] 🔍 Saving custom credentials toggle: ${isUsingCustomCredentials}`,
    );
    localStorage.setItem(
    "useCustomCredentials",
    JSON.stringify(isUsingCustomCredentials),
    );
    }, [isUsingCustomCredentials]);

    // Save custom credentials whenever they change
    useEffect(() => {
    if (clientId || clientSecret || redirectUri) {
    console.debug("[Settings] 🔍 Saving custom credentials to storage");
    localStorage.setItem(
    "customCredentials",
    JSON.stringify({
    clientId,
    clientSecret,
    redirectUri,
    }),
    );
    }
    }, [clientId, clientSecret, redirectUri]);

    // Initialize fields from customCredentials prop when it changes
    useEffect(() => {
    if (customCredentials) {
    // Use refs to avoid unnecessary state updates
    if (clientId !== customCredentials.clientId) {
    setClientId(customCredentials.clientId);
    }
    if (clientSecret !== customCredentials.clientSecret) {
    setClientSecret(customCredentials.clientSecret);
    }
    if (redirectUri !== customCredentials.redirectUri) {
    setRedirectUri(customCredentials.redirectUri);
    }
    }
    }, [customCredentials]);

    // Load backup schedule config on mount
    useEffect(() => {
    const loadScheduleConfig = async () => {
    try {
    console.debug("[Settings] Loading backup schedule config...");
    const config = await globalThis.electronBackup?.getScheduleConfig?.();
    if (config) {
    setScheduleConfig(config);
    }
    const status = await globalThis.electronBackup?.getBackupStatus?.();
    if (status) {
    setLastScheduledBackup(status.lastBackup);
    setNextScheduledBackup(status.nextBackup);
    }
    console.info("[Settings] ✅ Backup schedule config loaded");
    } catch (error) {
    console.error(
    "[Settings] ❌ Failed to load backup schedule config:",
    error,
    );
    }
    };
    loadScheduleConfig();
    }, []);

    // Listen for backup events
    useEffect(() => {
    const cleanupComplete = globalThis.electronBackup?.onBackupComplete?.(
    (data: { backupId: string; timestamp: number }) => {
    console.info("[Settings] Scheduled backup completed:", data.backupId);
    toast.success("Scheduled backup completed", {
    description: `Backup created at ${new Date(data.timestamp).toLocaleString()}`,
    });
    setLastScheduledBackup(data.timestamp);
    // Refresh status to get next backup time
    globalThis.electronBackup?.getBackupStatus?.().then(
    (
    status:
    | {
    isRunning: boolean;
    lastBackup: number | null;
    nextBackup: number | null;
    }
    | undefined,
    ) => {
    setNextScheduledBackup(status?.nextBackup ?? null);
    },
    );
    },
    );

    const cleanupError = globalThis.electronBackup?.onBackupError?.(
    (error: string) => {
    console.error("[Settings] Scheduled backup failed:", error);
    toast.error("Scheduled backup failed", {
    description: truncateToastMessage(error, 200).component,
    });
    },
    );

    return () => {
    cleanupComplete?.();
    cleanupError?.();
    };
    }, []);

    // Load update channel preference from storage on mount
    useEffect(() => {
    try {
    const savedChannel = storage.getItem(STORAGE_KEYS.UPDATE_CHANNEL);
    if (savedChannel === "beta" || savedChannel === "stable") {
    setUpdateChannel(savedChannel);
    console.debug(
    `[Settings] ✅ Loaded update channel preference: ${savedChannel}`,
    );
    }
    } catch (err) {
    console.error(
    "[Settings] ❌ Failed to load update channel preference:",
    err,
    );
    }
    }, []);

    // Save update channel preference to storage whenever it changes
    useEffect(() => {
    try {
    storage.setItem(STORAGE_KEYS.UPDATE_CHANNEL, updateChannel);
    console.debug(
    `[Settings] 💾 Saved update channel preference: ${updateChannel}`,
    );
    } catch (err) {
    console.error(
    "[Settings] ❌ Failed to save update channel preference:",
    err,
    );
    }
    }, [updateChannel]);

    // Load collapsed sections state from storage on mount
    useEffect(() => {
    try {
    const savedCollapsedSections = storage.getItem(
    STORAGE_KEYS.SETTINGS_COLLAPSED_SECTIONS,
    );
    if (savedCollapsedSections) {
    const parsed = JSON.parse(savedCollapsedSections);
    setCollapsedSections(parsed);
    console.debug("[Settings] ✅ Loaded collapsed sections state:", parsed);
    }
    } catch (err) {
    console.error(
    "[Settings] ❌ Failed to load collapsed sections state:",
    err,
    );
    }
    }, []);

    // Persist collapsed sections state to storage with debouncing
    useEffect(() => {
    const debounceTimer = setTimeout(() => {
    try {
    storage.setItem(
    STORAGE_KEYS.SETTINGS_COLLAPSED_SECTIONS,
    JSON.stringify(collapsedSections),
    );
    console.debug(
    "[Settings] 💾 Saved collapsed sections state:",
    collapsedSections,
    );
    } catch (err) {
    console.error(
    "[Settings] ❌ Failed to save collapsed sections state:",
    err,
    );
    }
    }, 500);

    return () => clearTimeout(debounceTimer);
    }, [collapsedSections]);

    /**
    * Toggles the collapsed state of a specific settings section.
    * @param sectionId - The ID of the section to toggle.
    * @source
    */
    const handleToggleSection = useCallback((sectionId: string) => {
    setCollapsedSections((prev) => ({
    ...prev,
    [sectionId]: !prev[sectionId],
    }));
    }, []);

    /**
    * Toggles all settings sections between fully collapsed and fully expanded states.
    * @source
    */
    const handleExpandCollapseAll = useCallback(() => {
    const allCollapsed = SECTION_IDS.every((id) => collapsedSections[id]);

    setCollapsedSections(
    SECTION_IDS.reduce(
    (acc, id) => ({
    ...acc,
    [id]: !allCollapsed,
    }),
    {},
    ),
    );
    }, [collapsedSections]);

    /**
    * Initiates AniList OAuth login flow with either custom or default credentials.
    * @source
    */
    const handleLogin = async () => {
    try {
    console.info(
    `[Settings] 🔐 Initiating AniList login (${isUsingCustomCredentials ? "custom" : "default"} credentials)`,
    );

    // Create credentials object based on source
    const credentials: ApiCredentials = isUsingCustomCredentials
    ? {
    source: "custom",
    clientId,
    clientSecret,
    redirectUri,
    }
    : {
    source: "default",
    clientId: DEFAULT_ANILIST_CONFIG.clientId,
    clientSecret: DEFAULT_ANILIST_CONFIG.clientSecret,
    redirectUri: DEFAULT_ANILIST_CONFIG.redirectUri,
    };

    await login(credentials);
    console.info("[Settings] ✅ Login initiated successfully");
    } catch (err: unknown) {
    console.error("[Settings] ❌ Login failed:", err);
    setError(
    createError(
    ErrorType.AUTH,
    err instanceof Error
    ? err.message
    : "Failed to authenticate with AniList. Please try again.",
    ),
    );
    }
    };

    /**
    * Cancels an ongoing OAuth authentication process.
    * @source
    */
    const handleCancelAuth = async () => {
    try {
    console.info("[Settings] 🚫 Cancelling authentication...");
    await cancelAuth();
    console.info("[Settings] ✅ Authentication cancelled successfully");
    } catch (err) {
    console.error("[Settings] ❌ Failed to cancel authentication:", err);
    setError(
    createError(
    ErrorType.AUTH,
    err instanceof Error
    ? err.message
    : "Failed to cancel authentication. Please try again.",
    ),
    );
    }
    };

    /**
    * Clears selected caches (localStorage, search cache, etc.) and displays result notification.
    * Iterates through browser storage items and removes those matching selected cache types.
    * @source
    */
    const handleClearCache = async () => {
    console.info("[Settings] 🗑️ Starting cache clear operation...");
    setIsCacheCleared(false);
    setIsClearing(true);
    setError(null);

    const anySelected = Object.values(cachesToClear).some(Boolean);
    if (!anySelected) {
    console.warn("[Settings] ⚠️ No cache types selected for clearing");
    setIsClearing(false);
    return;
    }

    console.debug(
    "[Settings] 🔍 Cache types selected:",
    Object.entries(cachesToClear)
    .filter(([, v]) => v)
    .map(([k]) => CACHE_TYPE_LABELS[k as keyof CachesToClear] ?? k),
    );

    const pushIfMissing = (arr: string[], value: string) => {
    if (!arr.includes(value)) arr.push(value);
    };

    const matchStorageKeyToRule = (
    key: string,
    value: string,
    rules: { patterns: string[]; target: string[] }[],
    ): boolean => {
    for (const { patterns, target } of rules) {
    if (patterns.some((p) => key.includes(p))) {
    pushIfMissing(target, value);
    return true;
    }
    }
    return false;
    };

    const getCacheKeysByType = (): Record<keyof CachesToClear, string[]> => {
    const base: Record<keyof CachesToClear, string[]> = {
    shouldClearAuthCache: [
    "authState",
    "customCredentials",
    "useCustomCredentials",
    ],
    shouldClearSearchCache: ["anilist_search_cache"],
    shouldClearMangaCache: ["anilist_manga_cache"],
    shouldClearReviewCache: [
    "match_results",
    "pending_manga",
    "matching_progress",
    ],
    shouldClearImportCache: [
    "kenmei_data",
    "import_history",
    "import_stats",
    ],
    shouldClearSyncCache: ["anilist_sync_history"],
    shouldClearSettingsCache: ["sync_config", "theme"],
    shouldClearOtherCache: ["cache_version"],
    };

    if (STORAGE_KEYS && typeof STORAGE_KEYS === "object") {
    const rules: { patterns: string[]; target: string[] }[] = [
    {
    patterns: ["MATCH", "REVIEW"],
    target: base.shouldClearReviewCache,
    },
    { patterns: ["IMPORT"], target: base.shouldClearImportCache },
    { patterns: ["CACHE"], target: base.shouldClearOtherCache },
    ];

    for (const [key, value] of Object.entries(STORAGE_KEYS)) {
    if (typeof value !== "string") continue;
    const matched = matchStorageKeyToRule(key, value, rules);
    if (!matched) {
    pushIfMissing(base.shouldClearOtherCache, value);
    }
    }
    }

    return base;
    };

    const clearExternalCaches = async (services: {
    clearSearchCache?: () => void;
    clearMangaCache?: () => void;
    cacheDebugger?: { resetAllCaches?: () => void };
    }) => {
    try {
    if (
    cachesToClear.shouldClearSearchCache &&
    typeof services.clearSearchCache === "function"
    ) {
    services.clearSearchCache();
    console.debug("[Settings] 🧹 Search cache cleared");
    }
    if (
    cachesToClear.shouldClearMangaCache &&
    typeof services.clearMangaCache === "function"
    ) {
    services.clearMangaCache();
    console.debug("[Settings] 🧹 Manga cache cleared");
    }
    if (
    cachesToClear.shouldClearSearchCache &&
    cachesToClear.shouldClearMangaCache &&
    services.cacheDebugger?.resetAllCaches
    ) {
    services.cacheDebugger.resetAllCaches();
    console.debug("[Settings] 🧹 All in-memory caches reset");
    }
    } catch (e) {
    console.warn("[Settings] Failed to clear external caches", e);
    }
    };

    const clearStorageKeys = (keys: string[]) => {
    for (const cacheKey of keys) {
    try {
    localStorage.removeItem(cacheKey);
    if (
    globalThis.electronStore &&
    typeof globalThis.electronStore.removeItem === "function"
    ) {
    globalThis.electronStore.removeItem(cacheKey);
    console.debug(
    `[Settings] 🧹 Cleared Electron Store cache: ${cacheKey}`,
    );
    }
    console.debug(`[Settings] 🧹 Cleared cache: ${cacheKey}`);
    } catch (e) {
    console.warn(`[Settings] Failed to clear cache: ${cacheKey}`, e);
    }
    }
    };

    const deleteIndexedDB = () => {
    try {
    const req = globalThis.indexedDB?.deleteDatabase("anilist-cache");
    if (!req) return;
    req.onsuccess = () =>
    console.debug(
    "[Settings] 🧹 Successfully deleted IndexedDB database",
    );
    req.onerror = () =>
    console.error("[Settings] Error deleting IndexedDB database");
    } catch (e) {
    console.warn("[Settings] Failed to clear IndexedDB:", e);
    }
    };

    const showResultSummary = () => {
    const clearedSummary = Object.entries(cachesToClear)
    .filter(([, selected]) => selected)
    .map(([type]) => {
    const label = CACHE_TYPE_LABELS[type as keyof CachesToClear] ?? type;
    return `✅ Cleared ${label} cache`;
    })
    .join("\n");

    try {
    globalThis.alert(
    "Cache Cleared Successfully!\n\n" +
    clearedSummary +
    "\n\nYou may need to restart the application for all changes to take effect.",
    );
    } catch (e) {
    console.warn("[Settings] Failed to show alert:", e);
    }
    };

    try {
    // Get all cache clearing functions
    const { clearMangaCache, cacheDebugger } = await import(
    "../api/matching/search-service"
    );
    const { clearSearchCache } = await import("../api/anilist/client");

    await clearExternalCaches({
    clearSearchCache,
    clearMangaCache,
    cacheDebugger,
    });

    const keysByType = getCacheKeysByType();
    const keysToRemove: string[] = [];

    for (const [type, selected] of Object.entries(cachesToClear) as [
    keyof CachesToClear,
    boolean,
    ][]) {
    if (!selected) continue;
    const keys = keysByType[type];
    keysToRemove.push(...keys);
    }

    const uniqueKeys = [...new Set(keysToRemove)];
    console.debug(
    "[Settings] 🧹 Clearing the following localStorage keys:",
    uniqueKeys,
    );

    clearStorageKeys(uniqueKeys);

    if (anySelected) deleteIndexedDB();

    console.info("[Settings] ✅ Selected caches cleared successfully");
    setIsCacheCleared(true);
    showResultSummary();
    setTimeout(() => setIsCacheCleared(false), 5000);
    } catch (err) {
    console.error("[Settings] ❌ Error clearing cache:", err);
    setError(
    createError(
    ErrorType.SYSTEM,
    err instanceof Error
    ? err.message
    : "An unexpected error occurred while clearing cache",
    ),
    );
    } finally {
    setIsClearing(false);
    }
    };

    /**
    * Dismisses error messages from display.
    * @source
    */
    const dismissError = () => {
    console.debug("[Settings] 🔍 Dismissing error message");
    setError(null);
    };

    /**
    * Handles import of backup file from user selection.
    * Validates and prompts for restore mode (Replace vs Merge) before restoring.
    * @source
    */
    const handleImportBackup = async () => {
    if (!selectedBackupFile) {
    setBackupValidationError("No file selected");
    return;
    }

    try {
    console.info(
    "[Settings] 📥 Importing backup file:",
    selectedBackupFile.name,
    );
    setIsRestoringBackup(true);
    setBackupValidationError(null);

    // Import and validate backup
    const backupData = await importBackupFromFile(selectedBackupFile);

    // Show confirmation dialog with details
    const shouldRestore = globalThis.confirm(
    `Restore backup from ${new Date(backupData.metadata.timestamp).toLocaleString()}?\n\n` +
    `App Version: ${backupData.metadata.appVersion}\n` +
    `This will overwrite your current data. Create a backup first if needed.`,
    );

    if (!shouldRestore) {
    console.info("[Settings] 🚫 Backup restore cancelled by user");
    setIsRestoringBackup(false);
    return;
    }

    // Show merge vs replace dialog
    const useMergeMode = globalThis.confirm(
    "How would you like to restore match results?\n\n" +
    "🔄 MERGE (OK): Combine existing matches with backup matches\n" +
    " • Preserves your current match selections\n" +
    " • Only MATCH_RESULTS are merged, other data is replaced\n\n" +
    "🔁 REPLACE (Cancel): Completely overwrite all data\n" +
    " • Discards current data entirely\n" +
    " • Fully reverts to backup state\n\n" +
    "Choose MERGE (OK) to preserve existing matches, or REPLACE (Cancel) to completely restore the backup.",
    );

    console.info(
    "[Settings] 📋 Restore mode selected:",
    useMergeMode ? "Merge" : "Replace",
    );

    // Restore backup with selected mode
    const result = await restoreBackup(backupData, { merge: useMergeMode });

    if (result.success) {
    console.info(
    "[Settings] ✅ Backup restored successfully (mode:",
    useMergeMode ? "Merge" : "Replace",
    ")",
    );
    recordEvent({
    type: "backup.restored",
    message: `Application data restored from backup (${useMergeMode ? "Merge" : "Replace"} mode)`,
    level: "info",
    metadata: { mergeMode: useMergeMode },
    });

    // Clear file selection
    setSelectedBackupFile(null);

    // Reload page to refresh all data
    setTimeout(() => {
    globalThis.location.reload();
    }, 1000);
    } else {
    throw new Error(result.errors.join("; "));
    }
    } catch (err) {
    console.error("[Settings] ❌ Failed to restore backup:", err);
    const message =
    err instanceof Error ? err.message : "Failed to restore backup";
    setBackupValidationError(message);
    recordEvent({
    type: "backup.error",
    message: `Backup restore failed: ${message}`,
    level: "error",
    });
    } finally {
    setIsRestoringBackup(false);
    }
    };

    /**
    * Handles restoring a backup file directly from the backup list.
    * @param file - The backup file to restore from
    * @source
    */
    const handleRestoreBackupFile = async (file: File) => {
    try {
    console.info("[Settings] 📥 Restoring backup from list file:", file.name);
    setIsRestoringBackup(true);
    setBackupValidationError(null);

    // Import and validate backup
    const backupData = await importBackupFromFile(file);

    // Show merge vs replace dialog
    const useMergeMode = globalThis.confirm(
    "How would you like to restore match results?\n\n" +
    "🔄 MERGE (OK): Combine existing matches with backup matches\n" +
    " • Preserves your current match selections\n" +
    " • Only MATCH_RESULTS are merged, other data is replaced\n\n" +
    "🔁 REPLACE (Cancel): Completely overwrite all data\n" +
    " • Discards current data entirely\n" +
    " • Fully reverts to backup state\n\n" +
    "Choose MERGE (OK) to preserve existing matches, or REPLACE (Cancel) to completely restore the backup.",
    );

    console.info(
    "[Settings] 📋 Restore mode selected:",
    useMergeMode ? "Merge" : "Replace",
    );

    // Restore backup with selected mode
    const result = await restoreBackup(backupData, { merge: useMergeMode });

    if (result.success) {
    console.info(
    "[Settings] ✅ Backup restored successfully (mode:",
    useMergeMode ? "Merge" : "Replace",
    ")",
    );
    recordEvent({
    type: "backup.restored",
    message: `Application data restored from backup (${useMergeMode ? "Merge" : "Replace"} mode)`,
    level: "info",
    metadata: { mergeMode: useMergeMode },
    });

    // Clear file selection
    setSelectedBackupFile(null);

    // Reload page to refresh all data
    setTimeout(() => {
    globalThis.location.reload();
    }, 1000);
    } else {
    throw new Error(result.errors.join("; "));
    }
    } catch (err) {
    console.error("[Settings] ❌ Failed to restore backup from list:", err);
    const message =
    err instanceof Error ? err.message : "Failed to restore backup";
    setBackupValidationError(message);
    recordEvent({
    type: "backup.error",
    message: `Backup restore failed: ${message}`,
    level: "error",
    });
    } finally {
    setIsRestoringBackup(false);
    }
    };

    /**
    * Handles changes to backup schedule configuration.
    * @source
    */
    const handleScheduleConfigChange = async (
    newConfig: BackupScheduleConfig,
    ) => {
    // Save previous config for potential revert
    const previousConfig = scheduleConfig;

    try {
    setScheduleConfig(newConfig);
    const result =
    await globalThis.electronBackup?.setScheduleConfig?.(newConfig);

    if (!result?.success) {
    // Revert to previous config if update failed
    setScheduleConfig(previousConfig);
    const errorMessage = result?.error || "Unknown error";
    console.error(
    "[Settings] Failed to update backup schedule:",
    errorMessage,
    );
    toast.error("Failed to update backup schedule", {
    description: truncateToastMessage(errorMessage, 200).component,
    });
    return;
    }

    console.info("[Settings] Backup schedule config updated:", newConfig);
    recordEvent({
    type: "backup.schedule-updated",
    message: `Backup schedule ${newConfig.enabled ? "enabled" : "disabled"} (${newConfig.interval})`,
    level: "info",
    metadata: { config: newConfig },
    });
    // Refresh status to get updated next backup time
    const status = await globalThis.electronBackup?.getBackupStatus?.();
    if (status) {
    setNextScheduledBackup(status.nextBackup);
    }
    } catch (error) {
    // Revert to previous config on exception
    setScheduleConfig(previousConfig);
    console.error("[Settings] Exception updating backup schedule:", error);
    toast.error("Failed to update backup schedule", {
    description: truncateToastMessage(
    error instanceof Error ? error.message : "Unknown error",
    200,
    ).component,
    });
    }
    };

    /**
    * Handles manual trigger of a scheduled backup.
    * @source
    */
    const handleTriggerScheduledBackup = async () => {
    try {
    setIsTriggeringBackup(true);
    console.info("[Settings] Manually triggering scheduled backup...");
    const result = await globalThis.electronBackup?.triggerBackup?.();
    if (result?.success) {
    toast.success("Backup created successfully", {
    description: `Backup ID: ${result.backupId}`,
    });
    // Refresh backup status from main process
    const status = await globalThis.electronBackup?.getBackupStatus?.();
    if (status) {
    setLastScheduledBackup(status.lastBackup);
    setNextScheduledBackup(status.nextBackup);
    }
    } else {
    throw new Error(result?.error || "Unknown error");
    }
    } catch (error) {
    console.error("[Settings] Failed to trigger backup:", error);
    toast.error("Failed to create backup", {
    description: truncateToastMessage(
    error instanceof Error ? error.message : "Unknown error",
    200,
    ).component,
    });
    } finally {
    setIsTriggeringBackup(false);
    }
    };

    /**
    * Handles file selection for backup import.
    * @source
    */
    const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (file) {
    setSelectedBackupFile(file);
    setBackupValidationError(null);
    console.debug("[Settings] 📄 File selected:", file.name);
    }
    };

    /**
    * Refreshes the page, clearing error states and reloading the view.
    * @source
    */
    const handleRefreshPage = () => {
    console.info("[Settings] 🔄 Refreshing page...");
    // Clear error states and status messages
    setError(null);
    globalThis.location.reload();
    };

    /**
    * Calculates remaining time until authentication token expiry.
    * @returns A formatted string representing hours and days remaining, or "unknown" if unavailable.
    * @source
    */
    const calculateExpiryTime = () => {
    if (!authState.expiresAt) return "unknown";

    const hoursRemaining = Math.round(
    (authState.expiresAt - Date.now()) / 3600000,
    );

    if (hoursRemaining > 24) {
    const days = Math.floor(hoursRemaining / 24);
    const hours = hoursRemaining % 24;
    return `${days}d ${hours}h`;
    }

    return `${hoursRemaining}h`;
    };

    /**
    * Checks for updates using the configured update channel preference.
    * Updates state with version info or error message.
    * @source
    */
    const handleCheckForUpdates = async () => {
    console.info("[Settings] 🔍 Checking for updates...");
    setIsCheckingUpdate(true);
    setUpdateError(null);
    setUpdateInfo(null);
    try {
    const result = await globalThis.electronUpdater.checkForUpdates({
    allowPrerelease: updateChannel === "beta",
    });

    if (result.updateAvailable && result.version) {
    setUpdateInfo({
    version: result.version,
    url: `https://github.com/RLAlpha49/KenmeiToAnilist/releases/tag/v${result.version}`,
    isBeta: updateChannel === "beta",
    });
    console.info(`[Settings] ✅ Update available: ${result.version}`);
    } else {
    console.info("[Settings] ℹ️ No updates available");
    // Show info message that no updates are available
    setUpdateError("You're already on the latest version!");
    }
    } catch (e) {
    console.error("[Settings] ❌ Error checking for updates:", e);
    setUpdateError(e instanceof Error ? e.message : "Unknown error");
    } finally {
    setIsCheckingUpdate(false);
    }
    };

    /**
    * Initiates download of an available update.
    * Progress is tracked via the useAutoUpdater hook.
    * @source
    */
    const handleDownloadUpdate = async () => {
    console.info("[Settings] 📥 Starting update download...");
    try {
    await globalThis.electronUpdater.downloadUpdate();
    console.info("[Settings] ✅ Update download initiated");
    } catch (e) {
    console.error("[Settings] ❌ Error downloading update:", e);
    setUpdateError(e instanceof Error ? e.message : "Download failed");
    }
    };

    /**
    * Installs the downloaded update by quitting the app and applying changes.
    * @source
    */
    const handleInstallUpdate = async () => {
    console.info("[Settings] 🔄 Installing update...");
    try {
    await globalThis.electronUpdater.installUpdate();
    console.info("[Settings] ✅ Update installed");
    } catch (e) {
    console.error("[Settings] ❌ Error installing update:", e);
    setUpdateError(e instanceof Error ? e.message : "Installation failed");
    }
    };

    const defaultCredentialStatus = useMemo(() => {
    const missing: string[] = [];
    const defaultClientId = DEFAULT_ANILIST_CONFIG.clientId?.trim() ?? "";
    const defaultClientSecret =
    DEFAULT_ANILIST_CONFIG.clientSecret?.trim() ?? "";
    if (!defaultClientId) missing.push("Client ID");
    if (!defaultClientSecret) missing.push("Client Secret");
    return {
    hasCredentials: missing.length === 0,
    missing,
    };
    }, []);

    const customCredentialStatus = useMemo(() => {
    const trimmedClientId = clientId.trim();
    const trimmedClientSecret = clientSecret.trim();
    const trimmedRedirectUri = redirectUri.trim();
    const missing: string[] = [];
    if (!trimmedClientId) missing.push("Client ID");
    if (!trimmedClientSecret) missing.push("Client Secret");
    if (!trimmedRedirectUri) missing.push("Redirect URI");
    return {
    isComplete: missing.length === 0,
    missing,
    };
    }, [clientId, clientSecret, redirectUri]);

    const credentialsBlocked = isUsingCustomCredentials
    ? !customCredentialStatus.isComplete
    : !defaultCredentialStatus.hasCredentials;
    const areAuthActionsDisabled = isLoading || credentialsBlocked;

    const expiresLabel = useMemo(
    () => (authState.isAuthenticated ? calculateExpiryTime() : undefined),
    [authState.expiresAt, authState.isAuthenticated],
    );

    const credentialSourceLabel = useMemo(
    () =>
    isUsingCustomCredentials ? "Custom credentials" : "Default credentials",
    [isUsingCustomCredentials],
    );

    // Computed value for button state
    const allCollapsed = SECTION_IDS.every((id) => collapsedSections[id]);

    return (
    <motion.div
    className="relative mx-auto max-w-[1200px] space-y-8 px-4 pb-12 pt-6 md:px-6"
    initial={{ opacity: 0 }}
    animate={{ opacity: 1 }}
    transition={{ duration: 0.4 }}
    >
    <SettingsHero
    isAuthenticated={authState.isAuthenticated}
    username={authState.username}
    avatarUrl={authState.avatarUrl}
    statusMessage={
    statusMessage && showStatusMessage && !error ? statusMessage : null
    }
    isLoading={isLoading}
    isLoginDisabled={areAuthActionsDisabled}
    onLogin={handleLogin}
    onRefreshToken={refreshToken}
    onLogout={logout}
    onClearStatus={() => setShowStatusMessage(false)}
    onCancelAuth={handleCancelAuth}
    credentialSourceLabel={credentialSourceLabel}
    expiresLabel={expiresLabel}
    >
    <AccountCredentialsSection
    authState={authState}
    isLoading={isLoading}
    isUsingCustomCredentials={isUsingCustomCredentials}
    onToggleCustomCredentials={setIsUsingCustomCredentials}
    clientId={clientId}
    onClientIdChange={setClientId}
    clientSecret={clientSecret}
    onClientSecretChange={setClientSecret}
    redirectUri={redirectUri}
    onRedirectUriChange={setRedirectUri}
    defaultCredentialStatus={defaultCredentialStatus}
    customCredentialStatus={customCredentialStatus}
    />
    </SettingsHero>

    <SettingsSearchBar
    searchInputRef={searchInputRef}
    searchQuery={searchQuery}
    searchResults={searchResults}
    onSearchChange={handleSearchChange}
    />

    {!searchQuery && (
    <div className="flex justify-end">
    <TooltipProvider>
    <Tooltip>
    <TooltipTrigger asChild>
    <Button
    variant="ghost"
    size="sm"
    onClick={handleExpandCollapseAll}
    className="text-xs text-slate-600 dark:text-slate-400"
    >
    {allCollapsed ? (
    <>
    <ChevronsUp className="mr-2 h-4 w-4" />
    Expand All
    </>
    ) : (
    <>
    <ChevronsDown className="mr-2 h-4 w-4" />
    Collapse All
    </>
    )}
    </Button>
    </TooltipTrigger>
    <TooltipContent side="top">
    {allCollapsed ? "Expand all sections" : "Collapse all sections"}
    </TooltipContent>
    </Tooltip>
    </TooltipProvider>
    </div>
    )}

    {error && (
    <motion.div
    className="rounded-3xl border border-rose-400/40 bg-rose-500/10 p-4 backdrop-blur-lg"
    initial={{ opacity: 0, y: -12 }}
    animate={{ opacity: 1, y: 0 }}
    transition={{ duration: 0.35 }}
    >
    <ErrorMessage
    message={error.message}
    type={error.type}
    onDismiss={dismissError}
    onRetry={error.type === ErrorType.AUTH ? handleLogin : undefined}
    />
    </motion.div>
    )}

    {isCacheCleared && (
    <motion.div
    initial={{ opacity: 0, y: 12 }}
    animate={{ opacity: 1, y: 0 }}
    transition={{ duration: 0.3 }}
    className="rounded-3xl border border-emerald-400/40 bg-emerald-500/10 px-4 py-3 text-sm text-emerald-100 backdrop-blur-lg"
    >
    <div className="flex items-center gap-2">
    <CheckCircle className="h-4 w-4" />
    <span>Selected caches cleared successfully.</span>
    </div>
    </motion.div>
    )}

    <SettingsTabsContainer
    searchQuery={searchQuery}
    searchResults={searchResults}
    highlightedSectionId={highlightedSectionId}
    matchConfig={matchConfig}
    syncConfig={syncConfig}
    isCustomThresholdEnabled={isCustomThresholdEnabled}
    cachesToClear={cachesToClear}
    isClearing={isClearing}
    isCacheCleared={isCacheCleared}
    isRestoringBackup={isRestoringBackup}
    selectedBackupFile={selectedBackupFile}
    backupValidationError={backupValidationError}
    isDebugEnabled={isDebugEnabled}
    isStorageDebuggerEnabled={isStorageDebuggerEnabled}
    isLogViewerEnabled={isLogViewerEnabled}
    isLogRedactionEnabled={isLogRedactionEnabled}
    isStateInspectorEnabled={isStateInspectorEnabled}
    isIpcViewerEnabled={isIpcViewerEnabled}
    isEventLoggerEnabled={isEventLoggerEnabled}
    isConfidenceTestExporterEnabled={isConfidenceTestExporterEnabled}
    isPerformanceMonitorEnabled={isPerformanceMonitorEnabled}
    onMatchConfigChange={saveMatchConfigWithEvent}
    onSyncConfigChange={saveSyncConfigWithEvent}
    onCustomThresholdToggle={setIsCustomThresholdEnabled}
    setSyncConfig={setSyncConfig}
    onCachesToClearChange={setCachesToClear}
    onClearCaches={handleClearCache}
    onRestoreBackup={handleImportBackup}
    onRestoreBackupFile={handleRestoreBackupFile}
    onFileSelect={handleFileSelect}
    scheduleConfig={scheduleConfig}
    nextScheduledBackup={nextScheduledBackup}
    lastScheduledBackup={lastScheduledBackup}
    isTriggeringBackup={isTriggeringBackup}
    onScheduleConfigChange={handleScheduleConfigChange}
    onTriggerBackup={handleTriggerScheduledBackup}
    onToggleDebug={toggleDebug}
    onStorageDebuggerChange={setIsStorageDebuggerEnabled}
    onLogViewerChange={setIsLogViewerEnabled}
    onLogRedactionChange={setIsLogRedactionEnabled}
    onStateInspectorChange={setIsStateInspectorEnabled}
    onIpcViewerChange={setIsIpcViewerEnabled}
    onEventLoggerChange={setIsEventLoggerEnabled}
    onConfidenceTestExporterChange={setIsConfidenceTestExporterEnabled}
    onPerformanceMonitorChange={setIsPerformanceMonitorEnabled}
    collapsedSections={collapsedSections}
    onToggleSection={handleToggleSection}
    />
    <UpdateManagementSection
    updateChannel={updateChannel}
    isCheckingUpdate={isCheckingUpdate}
    updateInfo={updateInfo}
    updateError={updateError}
    isDownloading={isDownloading}
    downloadProgress={downloadProgress}
    isDownloaded={isDownloaded}
    highlightedSectionId={highlightedSectionId}
    onUpdateChannelChange={setUpdateChannel}
    onCheckForUpdates={handleCheckForUpdates}
    onDownloadUpdate={handleDownloadUpdate}
    onInstallUpdate={handleInstallUpdate}
    onOpenExternal={handleOpenExternal}
    collapsedSections={collapsedSections}
    onToggleSection={handleToggleSection}
    />
    </motion.div>
    );
    }