import type { StateCreator } from "zustand";
import { DEFAULT_THEME_ID, DEFAULT_LIGHT_THEME_ID } from "../../styles/themes";
import type { ClaudeFlagDef } from "../../services/claudeFlags";
import type { AppState } from "../useAppStore";
import type { AgentBackendConfig } from "../../services/tauri";

export type ToolDisplayMode = "grouped" | "inline";

export interface SettingsSlice {
  worktreeBaseDir: string;
  setWorktreeBaseDir: (dir: string) => void;
  defaultTerminalAppId: string | null;
  setDefaultTerminalAppId: (appId: string | null) => void;
  /// Ordered list of app IDs surfaced at the top level of the workspace
  /// "Open in app" menu. `null` (the default) means "show all detected apps"
  /// — the existing behavior. Once curated, anything not in this list is
  /// reachable under the menu's "More" flyout. Persisted as the
  /// `workspace_apps_menu` app setting (`{ "shown": [...] }`).
  workspaceAppsMenuShown: string[] | null;
  setWorkspaceAppsMenuShown: (ids: string[] | null) => void;
  defaultBranches: Record<string, string>;
  setDefaultBranches: (branches: Record<string, string>) => void;
  terminalFontSize: number;
  setTerminalFontSize: (size: number) => void;
  uiFontSize: number;
  setUiFontSize: (size: number) => void;
  fontFamilySans: string;
  setFontFamilySans: (font: string) => void;
  fontFamilyMono: string;
  setFontFamilyMono: (font: string) => void;
  systemFonts: string[];
  setSystemFonts: (fonts: string[]) => void;
  currentThemeId: string;
  setCurrentThemeId: (id: string) => void;
  themeMode: "light" | "dark" | "system";
  setThemeMode: (mode: "light" | "dark" | "system") => void;
  themeDark: string;
  setThemeDark: (id: string) => void;
  themeLight: string;
  setThemeLight: (id: string) => void;

  // Sidebar display preferences
  /// Show running terminal commands under each workspace in the sidebar.
  /// Off by default — opt in via Settings → Appearance.
  showSidebarRunningCommands: boolean;
  setShowSidebarRunningCommands: (v: boolean) => void;
  toolDisplayMode: ToolDisplayMode;
  setToolDisplayMode: (mode: ToolDisplayMode) => void;
  extendedToolCallOutput: boolean;
  setExtendedToolCallOutput: (enabled: boolean) => void;

  // Claudette Terminal (read-only mirror of agent shell + workspace provisioning output)
  claudetteTerminalEnabled: boolean;
  setClaudetteTerminalEnabled: (enabled: boolean) => void;

  // Git / SCM
  /// Surface open issues + pull requests on the repo overview screen via
  /// the resolved SCM provider. Off by default. Persisted to app_settings
  /// as `project_view_issues_prs_enabled`; the backend Tauri commands
  /// short-circuit on the same key so a stale UI cannot trigger network
  /// calls. Hydrated in App.tsx at boot.
  projectViewIssuesPrsEnabled: boolean;
  setProjectViewIssuesPrsEnabled: (enabled: boolean) => void;

  // Experimental
  usageInsightsEnabled: boolean;
  setUsageInsightsEnabled: (enabled: boolean) => void;
  disable1mContext: boolean;
  setDisable1mContext: (v: boolean) => void;
  alternativeBackendsAvailable: boolean;
  setAlternativeBackendsAvailable: (available: boolean) => void;
  /// Whether the Pi harness was compiled into this binary. Reflects
  /// the Rust `pi-sdk` cargo feature: false in a build that opted out.
  /// The UI uses this to hide Pi cards and the Pi runtime option even
  /// when `alternativeBackendsAvailable` is true (a build can ship
  /// Codex Native alt-backend support without Pi).
  piSdkAvailable: boolean;
  setPiSdkAvailable: (available: boolean) => void;
  alternativeBackendsEnabled: boolean;
  setAlternativeBackendsEnabled: (enabled: boolean) => void;
  codexEnabled: boolean;
  setCodexEnabled: (enabled: boolean) => void;
  agentBackends: AgentBackendConfig[];
  setAgentBackends: (backends: AgentBackendConfig[]) => void;
  defaultAgentBackendId: string;
  setDefaultAgentBackendId: (id: string) => void;
  /**
   * Latest auth method reported by `get_claude_auth_status`. `oauth_token`
   * is the Claude subscription path — Pi must not surface Anthropic
   * models for those users (see ModelSelector + the Rust-side
   * `ensure_anthropic_not_routed_through_pi_via_oauth` gate).
   *
   * `null` = unknown / not signed in / probe hasn't run yet. Treated as
   * "no subscription gate" so the picker is fully visible until the
   * probe completes.
   */
  claudeAuthMethod: string | null;
  setClaudeAuthMethod: (method: string | null) => void;
  /// Which revision the Monaco git gutter compares the editor buffer
  /// against. "head" (default) shows uncommitted changes only; "merge_base"
  /// shows every change made on the workspace's branch since it diverged
  /// from the repo's base branch (matches the Changes panel).
  editorGitGutterBase: "head" | "merge_base";
  setEditorGitGutterBase: (value: "head" | "merge_base") => void;
  editorMinimapEnabled: boolean;
  setEditorMinimapEnabled: (enabled: boolean) => void;
  revealActiveFileInTree: boolean;
  setRevealActiveFileInTree: (enabled: boolean) => void;
  /// File-viewer chrome: soft-wrap long lines in Monaco. Mirrors the
  /// `editorMinimapEnabled` persistence pattern — hydrated from
  /// `editor_word_wrap` in app_settings on app boot, written through
  /// the View menu toggle. Default `true` so first-time users see the
  /// same behavior as the pre-menubar baseline (Monaco was configured
  /// with `wordWrap: "on"`).
  editorWordWrap: boolean;
  setEditorWordWrap: (enabled: boolean) => void;
  editorLineNumbersEnabled: boolean;
  setEditorLineNumbersEnabled: (enabled: boolean) => void;
  /// Multiplier applied to Monaco's font size. Persisted as
  /// `editor_font_zoom` (string-encoded float). Clamped to [0.7, 2]
  /// inside the setter so callers can't push the editor into a state
  /// the View > Reset Zoom menu item can't reach.
  editorFontZoom: number;
  setEditorFontZoom: (zoom: number) => void;
  keybindings: Record<string, string | null>;
  setKeybinding: (actionId: string, binding: string | null) => void;
  resetKeybinding: (actionId: string) => void;
  setKeybindings: (bindings: Record<string, string | null>) => void;
  voiceToggleHotkey: string | null;
  setVoiceToggleHotkey: (hotkey: string | null) => void;
  voiceHoldHotkey: string | null;
  setVoiceHoldHotkey: (hotkey: string | null) => void;

  /// Cached parse of `claude --help`. `null` until the section first loads
  /// (or the discovery task hasn't finished yet). Per-scope persisted values
  /// are fetched per-mount and live in the section component, not here.
  claudeFlagDefs: ClaudeFlagDef[] | null;
  setClaudeFlagDefs: (defs: ClaudeFlagDef[] | null) => void;
}

export const createSettingsSlice: StateCreator<
  AppState,
  [],
  [],
  SettingsSlice
> = (set) => ({
  worktreeBaseDir: "",
  setWorktreeBaseDir: (dir) => set({ worktreeBaseDir: dir }),
  defaultTerminalAppId: null,
  setDefaultTerminalAppId: (appId) => set({ defaultTerminalAppId: appId }),
  workspaceAppsMenuShown: null,
  setWorkspaceAppsMenuShown: (ids) => set({ workspaceAppsMenuShown: ids }),
  defaultBranches: {},
  setDefaultBranches: (branches) => set({ defaultBranches: branches }),
  terminalFontSize: 11,
  setTerminalFontSize: (size) => set({ terminalFontSize: size }),
  uiFontSize: 13,
  setUiFontSize: (size) => set({ uiFontSize: size }),
  fontFamilySans: "",
  setFontFamilySans: (font) => set({ fontFamilySans: font }),
  fontFamilyMono: "",
  setFontFamilyMono: (font) => set({ fontFamilyMono: font }),
  systemFonts: [],
  setSystemFonts: (fonts) => set({ systemFonts: fonts }),
  currentThemeId: DEFAULT_THEME_ID,
  setCurrentThemeId: (id) => set({ currentThemeId: id }),
  themeMode: "dark",
  setThemeMode: (mode) => set({ themeMode: mode }),
  themeDark: DEFAULT_THEME_ID,
  setThemeDark: (id) => set({ themeDark: id }),
  themeLight: DEFAULT_LIGHT_THEME_ID,
  setThemeLight: (id) => set({ themeLight: id }),

  showSidebarRunningCommands: false,
  setShowSidebarRunningCommands: (v) => set({ showSidebarRunningCommands: v }),
  toolDisplayMode: "grouped",
  setToolDisplayMode: (mode) => set({ toolDisplayMode: mode }),
  extendedToolCallOutput: false,
  setExtendedToolCallOutput: (enabled) =>
    set({ extendedToolCallOutput: enabled }),

  claudetteTerminalEnabled: true,
  setClaudetteTerminalEnabled: (enabled) =>
    set({ claudetteTerminalEnabled: enabled }),
  projectViewIssuesPrsEnabled: false,
  setProjectViewIssuesPrsEnabled: (enabled) =>
    set({ projectViewIssuesPrsEnabled: enabled }),
  usageInsightsEnabled: false,
  setUsageInsightsEnabled: (enabled) => set({ usageInsightsEnabled: enabled }),
  disable1mContext: false,
  setDisable1mContext: (v) => set({ disable1mContext: v }),
  alternativeBackendsAvailable: false,
  setAlternativeBackendsAvailable: (available) =>
    set((state) => ({
      alternativeBackendsAvailable: available,
      alternativeBackendsEnabled: available ? state.alternativeBackendsEnabled : false,
      codexEnabled: available ? state.codexEnabled : false,
    })),
  piSdkAvailable: false,
  setPiSdkAvailable: (available) => set({ piSdkAvailable: available }),
  alternativeBackendsEnabled: false,
  setAlternativeBackendsEnabled: (enabled) =>
    set((state) => ({
      alternativeBackendsEnabled: state.alternativeBackendsAvailable && enabled,
    })),
  codexEnabled: false,
  setCodexEnabled: (enabled) =>
    set((state) => ({
      codexEnabled: state.alternativeBackendsAvailable && enabled,
    })),
  agentBackends: [],
  setAgentBackends: (backends) => set({ agentBackends: backends }),
  defaultAgentBackendId: "anthropic",
  setDefaultAgentBackendId: (id) => set({ defaultAgentBackendId: id }),
  claudeAuthMethod: null,
  setClaudeAuthMethod: (method) => set({ claudeAuthMethod: method }),
  editorGitGutterBase: "head",
  setEditorGitGutterBase: (value) => set({ editorGitGutterBase: value }),
  editorMinimapEnabled: false,
  setEditorMinimapEnabled: (enabled) => set({ editorMinimapEnabled: enabled }),
  revealActiveFileInTree: true,
  setRevealActiveFileInTree: (enabled) =>
    set({ revealActiveFileInTree: enabled }),
  editorWordWrap: true,
  setEditorWordWrap: (enabled) => set({ editorWordWrap: enabled }),
  editorLineNumbersEnabled: true,
  setEditorLineNumbersEnabled: (enabled) =>
    set({ editorLineNumbersEnabled: enabled }),
  editorFontZoom: 1,
  setEditorFontZoom: (zoom) => {
    if (!Number.isFinite(zoom)) return;
    const clamped = Math.min(2, Math.max(0.7, zoom));
    set({ editorFontZoom: clamped });
  },
  keybindings: {},
  setKeybinding: (actionId, binding) =>
    set((state) => ({ keybindings: { ...state.keybindings, [actionId]: binding } })),
  resetKeybinding: (actionId) =>
    set((state) => {
      const next = { ...state.keybindings };
      delete next[actionId];
      return { keybindings: next };
    }),
  setKeybindings: (bindings) => set({ keybindings: bindings }),
  voiceToggleHotkey: null,
  setVoiceToggleHotkey: (hotkey) => set({ voiceToggleHotkey: hotkey }),
  voiceHoldHotkey: null,
  setVoiceHoldHotkey: (hotkey) => set({ voiceHoldHotkey: hotkey }),

  claudeFlagDefs: null,
  setClaudeFlagDefs: (defs) => set({ claudeFlagDefs: defs }),
});
