import type { ProjectEntry } from '@/lib/api/types';
import { getInjectedBootOutcome } from '@/lib/desktopBoot';
import type { DraftStarterRef } from '@/lib/draftStarters';
import type { MobileKeyboardMode } from '@/lib/mobileKeyboardMode';
import { getRuntimeApiBaseUrl, getRuntimeKey } from '@/lib/runtime-switch';
import { getRegisteredRuntimeAPIs } from '@/contexts/runtimeAPIRegistry';

type ManagedRemoteTunnelPreset = {
  id: string;
  name: string;
  hostname: string;
};

export type UpdateInfo = {
  available: boolean;
  version?: string;
  currentVersion: string;
  body?: string;
  date?: string;
  nextSuggestedCheckInSec?: number;
  // Web-specific fields
  packageManager?: string;
  updateCommand?: string;
};

export type UpdateProgress = {
  downloaded: number;
  total?: number;
};

export type SkillCatalogConfig = {
  id: string;
  label: string;
  source: string;
  subpath?: string;
  gitIdentityId?: string;
};

export type DesktopSettings = {
  themeId?: string;
  useSystemTheme?: boolean;
  themeVariant?: 'light' | 'dark';
  lightThemeId?: string;
  darkThemeId?: string;
  splashBgLight?: string;
  splashFgLight?: string;
  splashBgDark?: string;
  splashFgDark?: string;
  lastDirectory?: string;
  homeDirectory?: string;
  // Optional absolute path to `opencode` binary.
  opencodeBinary?: string;
  desktopLanAccessEnabled?: boolean;
  desktopKeepAwakeEnabled?: boolean;
  desktopUiPassword?: string;
  projects?: ProjectEntry[];
  activeProjectId?: string;
  securityScopedBookmarks?: string[];
  pinnedDirectories?: string[];
  showReasoningTraces?: boolean;
  collapsibleThinkingBlocks?: boolean;
  showDeletionDialog?: boolean;
  nativeNotificationsEnabled?: boolean;
  notificationMode?: 'always' | 'hidden-only';
  notifyOnSubtasks?: boolean;

  // Event toggles (which events trigger notifications)
  notifyOnCompletion?: boolean;
  notifyOnError?: boolean;
  notifyOnQuestion?: boolean;

  // Per-event notification templates
  notificationTemplates?: {
    completion: { title: string; message: string };
    error: { title: string; message: string };
    question: { title: string; message: string };
    subtask: { title: string; message: string };
  };

  // Summarization settings
  summarizeLastMessage?: boolean;
  summaryThreshold?: number;
  summaryLength?: number;
  maxLastMessageLength?: number;

  usageAutoRefresh?: boolean;
  usageRefreshIntervalMs?: number;
  usageDisplayMode?: 'usage' | 'remaining';
  usageShowPredValues?: boolean;
  usageDropdownProviders?: string[];
  usageSelectedModels?: Record<string, string[]>;  // Map of providerId -> selected model names
  usageCollapsedFamilies?: Record<string, string[]>;  // Map of providerId -> collapsed family IDs (UsagePage)
  usageExpandedFamilies?: Record<string, string[]>;  // Map of providerId -> EXPANDED family IDs (header dropdown - inverted)
  usageModelGroups?: Record<string, {
    customGroups?: Array<{id: string; label: string; models: string[]; order: number}>;
    modelAssignments?: Record<string, string>;  // modelName -> groupId
    renamedGroups?: Record<string, string>;  // groupId -> custom label
  }>;  // Per-provider custom model groups configuration
  autoDeleteEnabled?: boolean;
  autoDeleteAfterDays?: number;
  sessionRetentionAction?: 'archive' | 'delete';
  tunnelProvider?: string;
  tunnelMode?: 'quick' | 'managed-remote' | 'managed-local';
  tunnelBootstrapTtlMs?: number | null;
  tunnelSessionTtlMs?: number;
  managedLocalTunnelConfigPath?: string | null;
  managedRemoteTunnelHostname?: string;
  managedRemoteTunnelToken?: string | null;
  hasManagedRemoteTunnelToken?: boolean;
  managedRemoteTunnelPresets?: ManagedRemoteTunnelPreset[];
  managedRemoteTunnelSelectedPresetId?: string;
  managedRemoteTunnelPresetTokens?: Record<string, string>;
  defaultModel?: string; // format: "provider/model"
  defaultVariant?: string;
  defaultAgent?: string;
  defaultGitIdentityId?: string; // ''/undefined = unset, 'global' or profile id
  openInAppId?: string;
  autoCreateWorktree?: boolean;
  followUpBehavior?: 'steer' | 'queue';
  queueModeEnabled?: boolean;
  gitmojiEnabled?: boolean;
  defaultFileViewerPreview?: boolean;
  zenModel?: string;
  gitProviderId?: string;
  gitModelId?: string;
  pwaAppName?: string;
  pwaOrientation?: 'system' | 'portrait' | 'landscape';
  mobileKeyboardMode?: MobileKeyboardMode;
  inputSpellcheckEnabled?: boolean;
  showOpenCodeUpdateNotifications?: boolean;
  openCodeUpdateToastDismissedVersion?: string;
  showToolFileIcons?: boolean;
  showTurnChangedFiles?: boolean;
  showExpandedBashTools?: boolean;
  showExpandedEditTools?: boolean;
  timeFormatPreference?: 'auto' | '12h' | '24h';
  weekStartPreference?: 'auto' | 'sunday' | 'monday';
  chatRenderMode?: 'sorted' | 'live';
  messageStreamTransport?: 'auto' | 'ws' | 'sse';
  activityRenderMode?: 'collapsed' | 'summary';
  mermaidRenderingMode?: 'svg' | 'ascii';
  userMessageRenderingMode?: 'markdown' | 'plain';
  collapsibleUserMessages?: boolean;
  stickyUserHeader?: boolean;
  expandedEditorToolbar?: boolean;
  wideChatLayoutEnabled?: boolean;
  showSplitAssistantMessageActions?: boolean;
  fontSize?: number;
  terminalFontSize?: number;
  uiFont?: string;
  monoFont?: string;
  padding?: number;
  cornerRadius?: number;
  inputBarOffset?: number;
  shortcutOverrides?: Record<string, string>;

  favoriteModels?: Array<{ providerID: string; modelID: string }>;
  hiddenModels?: Array<{ providerID: string; modelID: string }>;
  collapsedModelProviders?: string[];
  recentModels?: Array<{ providerID: string; modelID: string }>;
  recentAgents?: string[];
  recentEfforts?: Record<string, string[]>;
  diffLayoutPreference?: 'dynamic' | 'inline' | 'side-by-side';
  gitChangesViewMode?: 'flat' | 'tree';
  directoryShowHidden?: boolean;
  filesViewShowGitignored?: boolean;

  // Message limit — controls fetch, trim, and Load More chunk size (default: 200)
  messageLimit?: number;

  // User-added skills catalogs (persisted to ~/.config/openchamber/settings.json)
  skillCatalogs?: SkillCatalogConfig[];
  // Opt-in to send anonymous usage reports for update checks (default: true)
  reportUsage?: boolean;

  // Global behavior prompt — synced to ~/.config/opencode/AGENTS.md
  globalBehaviorPrompt?: string;
  responseStyleEnabled?: boolean;
  responseStylePreset?: 'concise' | 'detailed' | 'mentor' | 'pushback' | 'noFiller' | 'matchEnergy' | 'warmPeer' | 'custom';
  responseStyleCustomInstructions?: string;
  dictationEnabled?: boolean;
  sttProvider?: 'local' | 'openai-compatible';
  sttServerUrl?: string;
  sttModel?: string;
  sttLocalModel?: string;
  sttLanguage?: string;
  // Global draft welcome starters (pinned commands/skills), persisted to settings.json
  draftStarters?: DraftStarterRef[];
};

type DesktopBridgeGlobal = {
  invoke?: (cmd: string, args?: Record<string, unknown>) => Promise<unknown>;
  openDialog?: (options: Record<string, unknown>) => Promise<unknown>;
  grantFileAccess?: (path: string) => Promise<unknown>;
  openExternal?: (url: string) => Promise<unknown>;
  listen?: (
    event: string,
    handler: (evt: { payload?: unknown }) => void,
  ) => Promise<() => void>;
};

type ElectronRuntimeGlobal = {
  runtime?: string;
  macVibrancy?: boolean;
  macVibrancySupported?: boolean;
};

const getElectronRuntime = (): ElectronRuntimeGlobal | null => {
  if (typeof window === 'undefined') return null;
  return (window as unknown as { __OPENCHAMBER_ELECTRON__?: ElectronRuntimeGlobal }).__OPENCHAMBER_ELECTRON__ ?? null;
};

const getDesktopBridge = (): DesktopBridgeGlobal | null => {
  if (typeof window === 'undefined') return null;
  return (window as unknown as { __OPENCHAMBER_DESKTOP__?: DesktopBridgeGlobal }).__OPENCHAMBER_DESKTOP__ ?? null;
};

export const isElectronShell = (): boolean => getElectronRuntime()?.runtime === 'electron';

export const hasDesktopInvoke = (): boolean => {
  return typeof getDesktopBridge()?.invoke === 'function';
};

export const canUseElectronDesktopIPC = (): boolean => isElectronShell() && hasDesktopInvoke();

export const invokeDesktop = async <T = unknown>(command: string, args?: Record<string, unknown>): Promise<T | null> => {
  const bridge = getDesktopBridge();
  if (typeof bridge?.invoke !== 'function') return null;
  return bridge.invoke(command, args ?? {}) as Promise<T>;
};

type LaunchAtLoginStatus = {
  supported: boolean;
  enabled: boolean;
};

type KeepAwakeStatus = {
  supported: boolean;
  enabled: boolean;
  active: boolean;
};

export const getDesktopLaunchAtLogin = async (): Promise<LaunchAtLoginStatus | null> => {
  if (!canUseElectronDesktopIPC() || !isDesktopLocalOriginActive()) {
    return null;
  }

  try {
    const result = await invokeDesktop<LaunchAtLoginStatus>('desktop_get_launch_at_login');
    if (!result || typeof result.supported !== 'boolean' || typeof result.enabled !== 'boolean') {
      return null;
    }
    return result;
  } catch (error) {
    console.warn('Failed to get launch at login status', error);
    return null;
  }
};

export const setDesktopLaunchAtLogin = async (enabled: boolean): Promise<LaunchAtLoginStatus | null> => {
  if (!canUseElectronDesktopIPC() || !isDesktopLocalOriginActive()) {
    return null;
  }

  try {
    const result = await invokeDesktop<LaunchAtLoginStatus>('desktop_set_launch_at_login', { enabled });
    if (!result || typeof result.supported !== 'boolean' || typeof result.enabled !== 'boolean') {
      return null;
    }
    return result;
  } catch (error) {
    console.warn('Failed to set launch at login status', error);
    return null;
  }
};

export const getDesktopKeepAwake = async (): Promise<KeepAwakeStatus | null> => {
  if (!canUseElectronDesktopIPC() || !isDesktopLocalOriginActive()) {
    return null;
  }

  try {
    const result = await invokeDesktop<KeepAwakeStatus>('desktop_get_keep_awake');
    if (!result || typeof result.supported !== 'boolean' || typeof result.enabled !== 'boolean' || typeof result.active !== 'boolean') {
      return null;
    }
    return result;
  } catch (error) {
    console.warn('Failed to get keep awake status', error);
    return null;
  }
};

export const setDesktopKeepAwake = async (enabled: boolean): Promise<KeepAwakeStatus | null> => {
  if (!canUseElectronDesktopIPC() || !isDesktopLocalOriginActive()) {
    return null;
  }

  try {
    const result = await invokeDesktop<KeepAwakeStatus>('desktop_set_keep_awake', { enabled });
    if (!result || typeof result.supported !== 'boolean' || typeof result.enabled !== 'boolean' || typeof result.active !== 'boolean') {
      return null;
    }
    return result;
  } catch (error) {
    console.warn('Failed to set keep awake status', error);
    return null;
  }
};

const normalizeOrigin = (raw: string): string | null => {
  const trimmed = raw.trim();
  if (!trimmed) return null;
  try {
    return new URL(trimmed).origin;
  } catch {
    try {
      return new URL(trimmed.endsWith('/') ? trimmed : `${trimmed}/`).origin;
    } catch {
      return null;
    }
  }
};

const parseUrl = (raw: string): URL | null => {
  const trimmed = raw.trim();
  if (!trimmed) return null;
  try {
    return new URL(trimmed);
  } catch {
    try {
      return new URL(trimmed.endsWith('/') ? trimmed : `${trimmed}/`);
    } catch {
      return null;
    }
  }
};

const normalizeHost = (rawHost: string): string => rawHost.replace(/^\[|\]$/g, '').toLowerCase();

const isLoopbackHost = (host: string): boolean => {
  const normalized = normalizeHost(host);
  return normalized === 'localhost' || normalized === '127.0.0.1' || normalized === '::1';
};

export const isDesktopLocalOriginActive = (): boolean => {
  if (typeof window === 'undefined') return false;
  if (!isDesktopShell()) return false;

  if (getRuntimeKey() === 'local') {
    return true;
  }

  const local = typeof window.__OPENCHAMBER_LOCAL_ORIGIN__ === 'string' ? window.__OPENCHAMBER_LOCAL_ORIGIN__ : '';
  const localUrl = parseUrl(local);
  const runtimeApiUrl = parseUrl(getRuntimeApiBaseUrl());

  if (!runtimeApiUrl && localUrl && getInjectedBootOutcome()?.target === 'local') {
    return true;
  }

  if (localUrl && runtimeApiUrl) {
    if (localUrl.origin === runtimeApiUrl.origin) {
      return true;
    }

    const localPort = localUrl.port || (localUrl.protocol === 'https:' ? '443' : '80');
    const runtimePort = runtimeApiUrl.port || (runtimeApiUrl.protocol === 'https:' ? '443' : '80');

    return (
      localUrl.protocol === runtimeApiUrl.protocol &&
      localPort === runtimePort &&
      isLoopbackHost(localUrl.hostname) &&
      isLoopbackHost(runtimeApiUrl.hostname)
    );
  }

  const currentUrl = parseUrl(window.location.origin);

  if (localUrl && currentUrl) {
    if (localUrl.origin === currentUrl.origin) {
      return true;
    }

    const localPort = localUrl.port || (localUrl.protocol === 'https:' ? '443' : '80');
    const currentPort = currentUrl.port || (currentUrl.protocol === 'https:' ? '443' : '80');

    return (
      localUrl.protocol === currentUrl.protocol &&
      localPort === currentPort &&
      isLoopbackHost(localUrl.hostname) &&
      isLoopbackHost(currentUrl.hostname)
    );
  }

  const localOrigin = normalizeOrigin(local);
  const currentOrigin = normalizeOrigin(window.location.origin) || window.location.origin;
  if (localOrigin && currentOrigin && localOrigin === currentOrigin) {
    return true;
  }

  return Boolean(currentUrl && isLoopbackHost(currentUrl.hostname));
};

export const isDesktopShell = (): boolean => {
  if (typeof window === 'undefined') return false;
  return isElectronShell();
};

export const startDesktopWindowDrag = async (): Promise<boolean> => {
  if (!isDesktopShell()) {
    return false;
  }

  try {
    await invokeDesktop('desktop_start_window_drag');
    return true;
  } catch {
    return false;
  }
};

export const isVSCodeRuntime = (): boolean => {
  const apis = getRegisteredRuntimeAPIs();
  return apis?.runtime?.isVSCode === true;
};

export const isWebRuntime = (): boolean => {
  const apis = getRegisteredRuntimeAPIs();
  const platform = apis?.runtime?.platform;
  if (platform === 'web') {
    return true;
  }
  if (platform === 'desktop' || platform === 'vscode') {
    return false;
  }
  // Default: anything that's not VSCode behaves like web (HTTP UI).
  return !isVSCodeRuntime();
};

export const getDesktopHomeDirectory = async (): Promise<string | null> => {
  if (typeof window !== 'undefined') {
    const embedded = window.__OPENCHAMBER_HOME__;
    if (embedded && embedded.length > 0) {
      return embedded;
    }
  }

  return null;
};

export const requestDirectoryAccess = async (
  directoryPath: string
): Promise<{ success: boolean; path?: string; projectId?: string; error?: string }> => {
  // Desktop shell on local instance: use native folder picker.
  if (hasDesktopInvoke() && isDesktopLocalOriginActive()) {
    try {
      const selected = await getDesktopBridge()?.openDialog?.({
        directory: true,
        multiple: false,
        title: 'Select Working Directory',
      });
      if (!selected || typeof selected !== 'string') {
        return { success: false, error: 'Directory selection cancelled' };
      }
      return { success: true, path: selected };
    } catch (error) {
      console.warn('Failed to request directory access', error);
      return { success: false, error: error instanceof Error ? error.message : String(error) };
    }
  }

  return { success: true, path: directoryPath };
};

const isDesktopFileGrantResult = (
  value: unknown
): value is { path?: unknown; outsideFileGrant?: unknown } => (
  value !== null && typeof value === 'object' && !Array.isArray(value)
);

export const requestFileAccess = async (
  options?: { filters?: Array<{ name: string; extensions: string[] }>; defaultPath?: string }
): Promise<{ success: boolean; path?: string; outsideFileGrant?: string; error?: string }> => {
  if (hasDesktopInvoke() && isDesktopLocalOriginActive()) {
    try {
      const selected = await getDesktopBridge()?.openDialog?.({
        directory: false,
        multiple: false,
        title: 'Select File',
        returnGrant: true,
        ...(options?.filters ? { filters: options.filters } : {}),
        ...(options?.defaultPath ? { defaultPath: options.defaultPath } : {}),
      });
      if (!selected) {
        return { success: false, error: 'File selection cancelled' };
      }
      if (typeof selected === 'string') {
        return { success: true, path: selected };
      }
      if (!isDesktopFileGrantResult(selected)) {
        return { success: false, error: 'File selection cancelled' };
      }
      const path = typeof selected.path === 'string' ? selected.path : '';
      if (!path) {
        return { success: false, error: 'File selection cancelled' };
      }
      return {
        success: true,
        path,
        outsideFileGrant: typeof selected.outsideFileGrant === 'string' ? selected.outsideFileGrant : undefined,
      };
    } catch (error) {
      console.warn('Failed to request file access', error);
      return { success: false, error: error instanceof Error ? error.message : String(error) };
    }
  }

  return { success: false, error: 'Native file picker not available' };
};

export const requestExistingFileAccess = async (
  path: string
): Promise<{ success: boolean; path?: string; outsideFileGrant?: string; error?: string }> => {
  const targetPath = typeof path === 'string' ? path.trim() : '';
  if (!targetPath) {
    return { success: false, error: 'Path is required' };
  }
  if (!hasDesktopInvoke() || !isDesktopLocalOriginActive()) {
    return { success: false, error: 'Native file access not available' };
  }

  try {
    const selected = await getDesktopBridge()?.grantFileAccess?.(targetPath);
    if (!isDesktopFileGrantResult(selected)) {
      return { success: false, error: 'File access was not granted' };
    }
    const grantedPath = typeof selected.path === 'string' ? selected.path : '';
    const outsideFileGrant = typeof selected.outsideFileGrant === 'string' ? selected.outsideFileGrant : '';
    if (!grantedPath || !outsideFileGrant) {
      return { success: false, error: 'File access was not granted' };
    }
    return { success: true, path: grantedPath, outsideFileGrant };
  } catch (error) {
    console.warn('Failed to request existing file access', error);
    return { success: false, error: error instanceof Error ? error.message : String(error) };
  }
};

export const startAccessingDirectory = async (
  directoryPath: string
): Promise<{ success: boolean; error?: string }> => {
  void directoryPath;
  return { success: true };
};

export const stopAccessingDirectory = async (
  directoryPath: string
): Promise<{ success: boolean; error?: string }> => {
  void directoryPath;
  return { success: true };
};

export const checkForDesktopUpdates = async (): Promise<UpdateInfo | null> => {
  if (!hasDesktopInvoke()) {
    return null;
  }

  try {
    const info = await invokeDesktop<UpdateInfo>('desktop_check_for_updates');
    return info as UpdateInfo;
  } catch (error) {
    console.warn('Failed to check for updates', error);
    return null;
  }
};

export const downloadDesktopUpdate = async (
  onProgress?: (progress: UpdateProgress) => void
): Promise<boolean> => {
  if (!hasDesktopInvoke()) {
    return false;
  }

  const bridge = getDesktopBridge();
  let unlisten: null | (() => void | Promise<void>) = null;
  let downloaded = 0;
  let total: number | undefined;

  try {
    if (typeof onProgress === 'function' && bridge?.listen) {
      unlisten = await bridge.listen('openchamber:update-progress', (evt) => {
        const payload = evt?.payload;
        if (!payload || typeof payload !== 'object') return;
        const data = payload as { event?: unknown; data?: unknown };
        const eventName = typeof data.event === 'string' ? data.event : null;
        const eventData = data.data && typeof data.data === 'object' ? (data.data as Record<string, unknown>) : null;

        if (eventName === 'Started') {
          downloaded = 0;
          total = typeof eventData?.contentLength === 'number' ? (eventData.contentLength as number) : undefined;
          onProgress({ downloaded, total });
          return;
        }

        if (eventName === 'Progress') {
          const d = eventData?.downloaded;
          const t = eventData?.total;
          if (typeof d === 'number') downloaded = d;
          if (typeof t === 'number') total = t;
          onProgress({ downloaded, total });
          return;
        }

        if (eventName === 'Finished') {
          onProgress({ downloaded, total });
        }
      });
    }

    await invokeDesktop('desktop_download_and_install_update');
    return true;
  } catch (error) {
    console.warn('Failed to download update', error);
    return false;
  } finally {
    if (unlisten) {
      try {
        const result = unlisten();
        if (result instanceof Promise) {
          await result;
        }
      } catch {
        // ignored
      }
    }
  }
};

export const restartToApplyUpdate = async (): Promise<boolean> => {
  if (!hasDesktopInvoke()) {
    return false;
  }

  return restartDesktopApp();
};

export const restartDesktopApp = async (): Promise<boolean> => {
  if (!hasDesktopInvoke()) {
    return false;
  }

  try {
    await invokeDesktop('desktop_restart');
    return true;
  } catch (error) {
    console.warn('Failed to restart desktop app', error);
    return false;
  }
};

export const getDesktopLanAddress = async (): Promise<string | null> => {
  if (!hasDesktopInvoke() || !isDesktopLocalOriginActive()) {
    return null;
  }

  try {
    const result = await invokeDesktop<string>('desktop_get_lan_address');
    return typeof result === 'string' && result.trim().length > 0 ? result.trim() : null;
  } catch (error) {
    console.warn('Failed to get desktop LAN address', error);
    return null;
  }
};

export const openDesktopPath = async (path: string, app?: string | null): Promise<boolean> => {
  if (!hasDesktopInvoke() || !isDesktopLocalOriginActive()) {
    return false;
  }

  const trimmed = path?.trim();
  if (!trimmed) {
    return false;
  }

  try {
    await invokeDesktop('desktop_open_path', {
      path: trimmed,
      app: typeof app === 'string' && app.trim().length > 0 ? app.trim() : undefined,
    });
    return true;
  } catch (error) {
    console.warn('Failed to open path', error);
    return false;
  }
};

export const revealDesktopPath = async (path: string): Promise<boolean> => {
  if (!hasDesktopInvoke() || !isDesktopLocalOriginActive()) {
    return false;
  }

  const trimmed = path?.trim();
  if (!trimmed) {
    return false;
  }

  try {
    await invokeDesktop('desktop_reveal_path', {
      path: trimmed,
    });
    return true;
  } catch {
    return openDesktopPath(trimmed);
  }
};

export const saveDesktopMarkdownFile = async (
  defaultFileName: string,
  content: string,
): Promise<string | null> => {
  if (!hasDesktopInvoke() || !isDesktopLocalOriginActive()) {
    return null;
  }

  const trimmedFileName = defaultFileName?.trim();
  if (!trimmedFileName) {
    return null;
  }

  try {
    const result = await invokeDesktop<string>('desktop_save_markdown_file', {
      defaultFileName: trimmedFileName,
      content,
    });
    return typeof result === 'string' && result.trim().length > 0 ? result : null;
  } catch (error) {
    console.warn('Failed to save markdown file', error);
    return null;
  }
};

export const openDesktopProjectInApp = async (
  projectPath: string,
  appId: string,
  appName: string,
): Promise<boolean> => {
  if (!hasDesktopInvoke() || !isDesktopLocalOriginActive()) {
    return false;
  }

  const trimmedProjectPath = projectPath?.trim();
  const trimmedAppId = appId?.trim();
  const trimmedAppName = appName?.trim();

  if (!trimmedProjectPath || !trimmedAppId || !trimmedAppName) {
    return false;
  }

  try {
    await invokeDesktop('desktop_open_in_app', {
      projectPath: trimmedProjectPath,
      appId: trimmedAppId,
      appName: trimmedAppName,
    });
    return true;
  } catch (error) {
    console.warn('Failed to open project in app', error);
    return false;
  }
};

export const openDesktopFileInApp = async (
  filePath: string,
  appId: string,
  appName: string,
): Promise<boolean> => {
  if (!hasDesktopInvoke() || !isDesktopLocalOriginActive()) {
    return false;
  }

  const trimmedFilePath = filePath?.trim();
  const trimmedAppId = appId?.trim();
  const trimmedAppName = appName?.trim();

  if (!trimmedFilePath || !trimmedAppId || !trimmedAppName) {
    return false;
  }

  try {
    await invokeDesktop('desktop_open_file_in_app', {
      filePath: trimmedFilePath,
      appId: trimmedAppId,
      appName: trimmedAppName,
    });
    return true;
  } catch (error) {
    console.warn('Failed to open file in app', error);
    return false;
  }
};

export type InstalledDesktopAppInfo = {
  name: string;
  iconDataUrl?: string | null;
};

export type FetchDesktopInstalledAppsResult = {
  apps: InstalledDesktopAppInfo[];
  success: boolean;
  hasCache: boolean;
  isCacheStale: boolean;
};

export const fetchDesktopInstalledApps = async (
  apps: string[],
  force?: boolean
): Promise<FetchDesktopInstalledAppsResult> => {
  if (!hasDesktopInvoke() || !isDesktopLocalOriginActive()) {
    return { apps: [], success: false, hasCache: false, isCacheStale: false };
  }

  const candidate = Array.isArray(apps) ? apps.filter((value) => typeof value === 'string') : [];
  if (candidate.length === 0) {
    return { apps: [], success: true, hasCache: false, isCacheStale: false };
  }

  try {
    const result = await invokeDesktop<unknown>('desktop_get_installed_apps', {
      apps: candidate,
      force: force === true ? true : undefined,
    });
    if (!result || typeof result !== 'object') {
      return { apps: [], success: false, hasCache: false, isCacheStale: false };
    }
    const payload = result as { apps?: unknown; hasCache?: unknown; isCacheStale?: unknown };
    if (!Array.isArray(payload.apps)) {
      return { apps: [], success: false, hasCache: false, isCacheStale: false };
    }
    const installedApps = payload.apps
      .filter((entry) => entry && typeof entry === 'object')
      .map((entry) => {
        const record = entry as { name?: unknown; iconDataUrl?: unknown };
        return {
          name: typeof record.name === 'string' ? record.name : '',
          iconDataUrl: typeof record.iconDataUrl === 'string' ? record.iconDataUrl : null,
        };
      })
      .filter((entry) => entry.name.length > 0);
    return {
      apps: installedApps,
      success: true,
      hasCache: payload.hasCache === true,
      isCacheStale: payload.isCacheStale === true,
    };
  } catch (error) {
    console.warn('Failed to fetch installed apps', error);
    return { apps: [], success: false, hasCache: false, isCacheStale: false };
  }
};
