import { Eventer } from "@tingwu/common";
import type { SphereContext } from "./sphereContext";

export interface SphereEventes<S extends Record<string, any> = {}> {
  stateChange: {
    key: keyof S;
    value: S[keyof S];
  };
}

export abstract class SphereController<
  S extends Record<string, any>,
  E extends Record<string, any>,
> extends Eventer<E> {
  context: SphereContext;

  state: S;

  readonly eventer: Eventer<SphereEventes<S>>;

  abstract key: string;

  constructor(context: SphereContext, state: S) {
    super();
    this.context = context;
    this.state = state;
    this.eventer = new Eventer<SphereEventes<S>>();
  }

  getAllState() {
    return this.state;
  }

  setAllState(state: S) {
    this.state = state;
  }

  setState<K extends keyof S>(key: K, value: S[K]) {
    this.state[key] = value;
    this.emitStateChange({
      key,
      value,
    });
  }

  getState<K extends keyof S>(key: K): S[K] {
    return this.state[key];
  }

  onStateChange(callback: (event: SphereEventes<S>["stateChange"]) => void) {
    return this.eventer.on("stateChange", callback);
  }

  offStateChange(callback: (event: SphereEventes<S>["stateChange"]) => void) {
    return this.eventer.off("stateChange", callback);
  }

  emitStateChange(event: SphereEventes<S>["stateChange"]) {
    return this.eventer.emit("stateChange", event);
  }
}
