/**
 * A minimal, type-safe reactive signal with zero dependencies.
 *
 * This is the seed of the framework's reactivity. Today it powers nothing on
 * its own, but it is shaped so client islands (and later the `.wrn` compiler's
 * `state` blocks) can build reactive bindings on top of it.
 *
 *   const count = signal(0)
 *   count.get()                 // 0
 *   count.set(1)                // notifies subscribers
 *   const off = count.subscribe(v => console.log(v))
 *   off()                       // unsubscribe
 */

export type Subscriber<T> = (value: T) => void;
export type Unsubscribe = () => void;

export interface Signal<T> {
  /** Read the current value. */
  get(): T;
  /** Write a new value; subscribers run only when the value actually changes. */
  set(next: T): void;
  /** Apply a function to the current value. */
  update(fn: (current: T) => T): void;
  /** Subscribe to changes; returns an unsubscribe function. */
  subscribe(fn: Subscriber<T>): Unsubscribe;
}

export function signal<T>(initial: T): Signal<T> {
  let value = initial;
  const subscribers = new Set<Subscriber<T>>();

  return {
    get(): T {
      return value;
    },
    set(next: T): void {
      if (Object.is(next, value)) return; // skip no-op updates
      value = next;
      // Iterate a copy so a subscriber may unsubscribe during notification.
      for (const fn of [...subscribers]) fn(value);
    },
    update(fn: (current: T) => T): void {
      this.set(fn(value));
    },
    subscribe(fn: Subscriber<T>): Unsubscribe {
      subscribers.add(fn);
      return () => {
        subscribers.delete(fn);
      };
    },
  };
}
