import { useSyncExternalStore } from 'react';

type Listener = () => void;
type Updater<T> = (prev: T) => T;
type Middleware<T> = (prev: T, next: T) => void;

interface StoreOptions<T> {
  name?: string;
  persist?: boolean;
  devtools?: boolean;
  middlewares?: Middleware<T>[];
}

function getKey(name?: string) {
  return `__stately__${name ?? 'default'}`;
}

function loadPersistedState<T>(defaultState: T, options?: StoreOptions<T>): T {
  if (typeof window === 'undefined' || !options?.persist) return defaultState;
  const raw = localStorage.getItem(getKey(options.name));
  if (!raw) return defaultState;
  try {
    return JSON.parse(raw);
  } catch {
    return defaultState;
  }
}

export function createStore<T>(
  initialValue: T,
  options?: StoreOptions<T>
): () => [T, (updater: Updater<T>) => void] {
  let state: T = loadPersistedState(initialValue, options);
  const listeners = new Set<Listener>();
  const middlewares = options?.middlewares ?? [];

  const notify = () => {
    listeners.forEach((listener) => listener());
    if (options?.devtools && typeof window !== 'undefined') {
      window.__STATELY_DEVTOOLS__?.({ name: options.name, state });
    }
  };

  const setState = (updater: Updater<T>) => {
    const nextState = updater(state);
    middlewares.forEach((mw) => mw(state, nextState));
    state = nextState;
    if (options?.persist) {
      localStorage.setItem(getKey(options.name), JSON.stringify(state));
    }
    notify();
  };

  const subscribe = (listener: Listener) => {
    listeners.add(listener);
    return () => listeners.delete(listener);
  };

  const useStore = (): [T, (updater: Updater<T>) => void] => {
    const snapshot = useSyncExternalStore(subscribe, () => state);
    return [snapshot, setState];
  };

  return useStore;
}

// Global devtools extension hook
declare global {
  interface Window {
    __STATELY_DEVTOOLS__?: (payload: { name?: string; state: unknown }) => void;
  }
}
