/**
 * Zustand store for user preferences: locale, font-scale, contrast.
 * Persisted to localStorage under the key `multideal_prefs`.
 */

import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { applyClientLocale, type Locale } from './index';

export type FontScale = 'S' | 'M' | 'L' | 'XL' | 'XXL' | 'XXXL';
export type ContrastMode = 'normal' | 'high';

/** Numeric multipliers that match the CSS token comment in tokens.css */
const FONT_SCALE_MAP: Record<FontScale, string> = {
  S: '0.9',
  M: '1',
  L: '1.125',
  XL: '1.25',
  XXL: '1.5',
  XXXL: '2',
};

export interface PrefsState {
  locale: Locale;
  fontScale: FontScale;
  contrast: ContrastMode;
  setLocale: (locale: Locale) => void;
  setFontScale: (fontScale: FontScale) => void;
  setContrast: (contrast: ContrastMode) => void;
}

/**
 * Resolve the seed locale for the store's initial state.
 *
 * - Server (no `document`): always returns the default `'he'`. This store is
 *   module-level state shared by every request in the isolate, so it cannot
 *   hold a per-request locale; the React bindings read the request locale
 *   ambiently instead (see `./request-locale`).
 * - Client: reads `<html lang>` (set by Astro before any JS runs), guaranteeing
 *   the store's first-render value matches the server-rendered HTML.
 */
function initialLocale(): Locale {
  if (typeof document === 'undefined') return 'he';
  // Read the server-emitted attribute, not html.lang — LocaleScript mutates lang
  // before this runs, causing a mismatch when the user's stored locale differs
  // from the server-rendered locale.
  return document.documentElement.dataset.serverLocale === 'en' ? 'en' : 'he';
}

/**
 * Imperative seed for the store's `locale` field. Called by `LocaleProvider`
 * at module evaluation / render time so SSR uses the request locale rather than
 * the default `'he'`. Safe to call multiple times — later calls overwrite.
 *
 * Use only for initial hydration sync. User-driven locale changes must go
 * through `setLocale` so persistence + side effects fire.
 */
export function seedLocale(locale: Locale): void {
  if (usePrefsStore.getState().locale === locale) return;
  usePrefsStore.setState({ locale });
}

export const usePrefsStore = create<PrefsState>()(
  persist(
    (set) => ({
      locale: initialLocale(),
      fontScale: 'M' as FontScale,
      contrast: 'normal' as ContrastMode,

      setLocale(locale: Locale) {
        set({ locale });
        applyClientLocale(locale);
      },

      setFontScale(fontScale: FontScale) {
        set({ fontScale });
        if (typeof document !== 'undefined') {
          document.documentElement.style.setProperty('--font-scale', FONT_SCALE_MAP[fontScale]);
        }
      },

      setContrast(contrast: ContrastMode) {
        set({ contrast });
        if (typeof document !== 'undefined') {
          if (contrast === 'high') {
            document.documentElement.setAttribute('data-contrast', 'high');
          } else {
            document.documentElement.removeAttribute('data-contrast');
          }
        }
      },
    }),
    {
      name: 'multideal_prefs',
      // Only persist locale, fontScale, contrast - not the action functions
      partialize: (state) => ({
        locale: state.locale,
        fontScale: state.fontScale,
        contrast: state.contrast,
      }),
      // <html lang> (server-resolved from ?lang= → cookie → default 'he')
      // wins over persisted localStorage on rehydrate. Prevents stale persisted
      // locale from overriding URL/cookie signal in any island that subscribes
      // to the store (SkipLink, SiteFooter, useT consumers).
      merge: (persistedState, currentState) => ({
        ...currentState,
        ...(persistedState as Partial<PrefsState>),
        locale: currentState.locale,
      }),
      // Prevent synchronous localStorage rehydration during React 19 SSR hydration pass.
      // LocaleProvider calls rehydrate() in useEffect after mount.
      skipHydration: true,
    },
  ),
);
