// AUTO-GENERATED by stele — do not edit.
// Framework-agnostic locale store — the single source of truth for the active
// locale. Tracks a preference ("system" = follow the device, or a pinned
// Locale), is observable (subscribe) and persistable. React binds to it via
// useSyncExternalStore; non-React code reads/writes it directly.
import { createStele, type Stele, type Locale } from "./stele.gen";

export type { Stele, Locale };

/** What the user wants: follow the device ("system") or a pinned locale. */
export type LocalePref = "system" | Locale;

/** Pluggable persistence — supply your own AsyncStorage / localStorage adapter. */
export interface LocaleStorage {
  load(): Promise<LocalePref | null> | LocalePref | null;
  save(pref: LocalePref): Promise<void> | void;
}

const LOCALES = ["en", "es", "pl"] as const;
const CANONICAL: Locale = "en";

let _locale: Locale = CANONICAL;
let _current: Stele = createStele(_locale);
let _pref: LocalePref = "system";
let _deviceLocales: () => readonly string[] = () => [];
let _storage: LocaleStorage | null = null;
const listeners = new Set<() => void>();

function notify(): void {
  for (const listener of listeners) listener();
}

function resolve(locale: Locale): void {
  if (locale === _locale) return;
  _locale = locale;
  _current = createStele(locale);
}

/** The active (resolved) locale. */
export function getLocale(): Locale {
  return _locale;
}

/** The accessor bound to the active locale (stable until the locale changes). */
export function getStele(): Stele {
  return _current;
}

/** Whether the active locale is currently following the device ("system"). */
export function isFollowingDevice(): boolean {
  return _pref === "system";
}

/** Subscribe to locale / preference changes; returns an unsubscribe function. */
export function subscribeLocale(listener: () => void): () => void {
  listeners.add(listener);
  return () => listeners.delete(listener);
}

/** Pin an explicit locale (stops following the device); persists the choice. */
export function setLocale(locale: Locale): void {
  _pref = locale;
  resolve(locale);
  notify();
  void _storage?.save(locale);
}

/** Follow the device locale from now on; re-resolves now and persists "system". */
export function followDevice(): void {
  _pref = "system";
  resolve(resolveLocale(_deviceLocales()));
  notify();
  void _storage?.save("system");
}

/**
 * Re-read the device locale, but only while in system mode. Wire this to an
 * AppState "active" listener to track the OS language changing at runtime.
 */
export function syncDevice(): void {
  if (_pref !== "system") return;
  const next = resolveLocale(_deviceLocales());
  if (next === _locale) return;
  resolve(next);
  notify();
}

/** Match arbitrary BCP-47 tags (e.g. device locales) to a supported Locale. */
export function resolveLocale(tags: readonly string[]): Locale {
  for (const tag of tags) {
    const lower = tag.toLowerCase();
    const exact = LOCALES.find((l) => l.toLowerCase() === lower);
    if (exact) return exact;
    const primary = lower.split("-")[0];
    const base = LOCALES.find((l) => l.toLowerCase().split("-")[0] === primary);
    if (base) return base;
  }
  return CANONICAL;
}

/**
 * Initialize the store once at startup: restore the saved preference (or default
 * to following the device), wire the device-locale source, and apply the result.
 * Pass `deviceLocales` (e.g. `() => Localization.locales`) to enable system mode.
 * Returns the resolved active locale. Call once before your first render.
 */
export async function initLocale(opts?: {
  storage?: LocaleStorage;
  deviceLocales?: () => readonly string[];
  initial?: LocalePref;
}): Promise<Locale> {
  _storage = opts?.storage ?? null;
  _deviceLocales = opts?.deviceLocales ?? (() => []);
  let pref: LocalePref | null = opts?.initial ?? null;
  if (pref === null && _storage !== null) pref = await _storage.load();
  _pref = pref ?? "system";
  if (_pref !== "system" && !(LOCALES as readonly Locale[]).includes(_pref)) {
    _pref = "system";
  }
  resolve(_pref === "system" ? resolveLocale(_deviceLocales()) : _pref);
  notify();
  return _locale;
}
