export type StoreKind = "global" | "page";
export type StoreRuntime = "shared" | "client" | "server" | "legacy";
export type PersistenceStorage = "memory" | "session" | "local";
/** Broad callable constraint that preserves each action's concrete parameters and return type. */
export type StoreFunction = (...args: any[]) => unknown;

export type StoreCombinedState<
  S extends object,
  CS extends object = Record<string, never>,
  SS extends object = Record<string, never>,
> = S & Partial<CS> & Partial<SS>;

export interface StorePersistenceConfig<S extends object> {
  storage: PersistenceStorage;
  include: Array<keyof S & string>;
  version: number;
  migrate?: (value: unknown, fromVersion: number, toVersion: number) => Partial<S>;
  validate?: (value: unknown) => Partial<S> | null;
}

export interface StoreLifecycleContext<S extends object> {
  state: S;
  runtime: "server" | "client";
  request?: unknown;
  routeId?: string;
}

export interface StoreActionDefinition<S extends object, F extends StoreFunction = StoreFunction> {
  runtime: StoreRuntime;
  handler: (context: StoreActionContext<S>, ...args: Parameters<F>) => ReturnType<F>;
}

export interface StoreDefinition<
  S extends object,
  C extends object = Record<string, never>,
  A extends Record<string, StoreFunction> = Record<string, StoreFunction>,
  CS extends object = Record<string, never>,
  SS extends object = Record<string, never>,
> {
  name: string;
  kind: StoreKind;
  createSharedState: () => S;
  createClientState?: () => CS;
  createServerState?: () => SS;
  computed?: {
    [K in keyof C]: (state: Readonly<StoreCombinedState<S, CS, SS>>) => C[K];
  };
  actions?: {
    [K in keyof A]:
      | StoreActionDefinition<StoreCombinedState<S, CS, SS>, A[K]>
      | Array<StoreActionDefinition<StoreCombinedState<S, CS, SS>, A[K]>>;
  };
  persist?: StorePersistenceConfig<StoreCombinedState<S, CS, SS>>;
  lifecycle?: {
    serverInit?: (
      context: StoreLifecycleContext<StoreCombinedState<S, CS, SS>>,
    ) => void | Promise<void>;
    clientInit?: (
      context: StoreLifecycleContext<StoreCombinedState<S, CS, SS>>,
    ) => void | Promise<void>;
    hydrate?: (
      context: StoreLifecycleContext<StoreCombinedState<S, CS, SS>>,
    ) => void | Promise<void>;
    dispose?: (
      context: StoreLifecycleContext<StoreCombinedState<S, CS, SS>>,
    ) => void | Promise<void>;
  };
}

export interface StoreActionContext<S extends object> {
  state: S;
  snapshot(): Readonly<S>;
  reset(): void;
  runtime: "server" | "client";
  request?: unknown;
  routeId?: string;
}

export interface StoreMutation {
  store: string;
  action: string;
  changed: string[];
  before: Readonly<Record<string, unknown>>;
  after: Readonly<Record<string, unknown>>;
  timestamp: number;
}

export interface StoreInstanceCore<
  S extends object,
  C extends object,
  A extends Record<string, StoreFunction>,
> {
  readonly name: string;
  readonly kind: StoreKind;
  readonly state: Readonly<S>;
  readonly computed: Readonly<C>;
  readonly actions: A;
  /** Internal initialization promise. `whenReady` avoids colliding with store state named `ready`. */
  readonly whenReady: Promise<void>;
  reset(): void;
  snapshot(): Readonly<S>;
  hydrate(value: Partial<S>): void;
  serialize(): Partial<S>;
  subscribe(listener: (snapshot: Readonly<S>, mutation?: StoreMutation) => void): () => void;
  dispose(): Promise<void>;
}

export type StoreInstance<
  S extends object,
  C extends object,
  A extends Record<string, StoreFunction>,
> = StoreInstanceCore<S, C, A> & Readonly<S> & Readonly<C> & A;
