import { create } from 'zustand';
import type { FitMode } from '@core/rendering';
import type { UiTheme } from '@core/theme';
import type { ChartThemeSelection } from '@core/vega-themes';
import type { ModalName } from '../modals/types';

/** Default data-inspector height (px) when first expanded, before any drag. */
const DATA_INSPECTOR_DEFAULT_HEIGHT = 220;

/** Floor (px) for the inspector and for the chart above it while the divider drags. */
const DATA_INSPECTOR_MIN_HEIGHT = 96;
const CHART_MIN_HEIGHT = 120;

/**
 * Clamp a desired inspector height so it keeps its own minimum and leaves the
 * chart above it at least its minimum. `availForBoth` is the height the chart and
 * inspector share (the preview body, minus the divider). Pure — the single place
 * the divider constraint lives, unit-tested without a DOM. Mirrors PanesStore's
 * `clampSideWidth`.
 */
export function clampInspectorHeight(desired: number, availForBoth: number): number {
  const max = Math.max(DATA_INSPECTOR_MIN_HEIGHT, availForBoth - CHART_MIN_HEIGHT);
  return Math.max(DATA_INSPECTOR_MIN_HEIGHT, Math.min(desired, max));
}

/**
 * The inspector's 0–100 position for the divider's `aria-valuenow` (WAI-ARIA APG →
 * Window Splitter): 0 = inspector at its minimum, 100 = at its maximum (chart at
 * its minimum). Null when the span has no range, so the caller omits the attribute.
 */
export function inspectorHeightValue(height: number, availForBoth: number): number | null {
  const min = DATA_INSPECTOR_MIN_HEIGHT;
  const max = Math.max(min, availForBoth - CHART_MIN_HEIGHT);
  if (max <= min) return null;
  const pct = ((height - min) / (max - min)) * 100;
  return Math.round(Math.min(100, Math.max(0, pct)));
}

/**
 * Centralized cross-cutting application state, as a Zustand store. Keep this
 * lean — durable, feature-specific state (snippets, datasets, settings) lands
 * in its own store module (e.g. stores/SnippetStore) as the app grows.
 *
 * Usable inside React via the `useAppStore` hook (with a selector) and outside
 * React via `useAppStore.getState()` / `.setState()` / `.subscribe()` — see
 * docs/architecture/01-state-and-stores.md.
 */

export interface AppState {
  /** Active UI theme; mirrored onto <html data-theme> by a subscriber. */
  uiTheme: UiTheme;
  /** Preview sizing mode (spec §04); persisted to Settings as `previewFitMode`. */
  previewFitMode: FitMode;
  /** Chart theme selection (spec §04); persisted to Settings as `chartTheme`. */
  chartTheme: ChartThemeSelection;
  /**
   * Whether the live-preview data inspector is expanded (spec §04). A preview-pane
   * preference like `previewFitMode`; persisted to Settings as `dataInspectorOpen`.
   */
  dataInspectorOpen: boolean;
  /**
   * Height (px) of the expanded data inspector — set by its resizable divider, so
   * the chart above keeps the rest of the pane. Persisted as `dataInspectorHeight`.
   */
  dataInspectorHeight: number;
  /** The currently open modal, or null. */
  activeModal: ModalName | null;

  setTheme: (theme: UiTheme) => void;
  /** Flip between light and dark — the header ThemeToggle's action. */
  toggleTheme: () => void;
  /** Set the preview fit mode — the Live Preview Fit control's action. */
  setPreviewFitMode: (mode: FitMode) => void;
  /** Set the chart theme — the Live Preview settings cluster's action. */
  setChartTheme: (theme: ChartThemeSelection) => void;
  /** Show/hide the data inspector — its disclosure toggle. */
  setDataInspectorOpen: (open: boolean) => void;
  /** Set the data inspector's height (caller clamps via `clampInspectorHeight`). */
  setDataInspectorHeight: (height: number) => void;
  /**
   * Low-level modal setter — the single primitive that mutates `activeModal`.
   * High-level open/close (snapshot for unsaved-change detection, URL sync,
   * discard confirmation) lives in the modal coordinator (docs/architecture/03),
   * which calls this; arrives with the modal system in M3.
   */
  setActiveModal: (modal: ModalName | null) => void;
}

export const useAppStore = create<AppState>((set) => ({
  uiTheme: 'light',
  previewFitMode: 'default',
  chartTheme: 'astrolabe',
  dataInspectorOpen: false,
  dataInspectorHeight: DATA_INSPECTOR_DEFAULT_HEIGHT,
  activeModal: null,

  setTheme: (uiTheme) => set({ uiTheme }),
  toggleTheme: () => set((s) => ({ uiTheme: s.uiTheme === 'dark' ? 'light' : 'dark' })),
  setPreviewFitMode: (previewFitMode) => set({ previewFitMode }),
  setChartTheme: (chartTheme) => set({ chartTheme }),
  setDataInspectorOpen: (dataInspectorOpen) => set({ dataInspectorOpen }),
  setDataInspectorHeight: (dataInspectorHeight) => set({ dataInspectorHeight }),
  setActiveModal: (activeModal) => set({ activeModal }),
}));
