import { ExtractNever, isFunction, keys } from "../core";
import { OBSERVERS_PATH } from "./const";
import { Observer } from "./Observer";
import { Reactive } from "./Reactive";
import { injectReactiveSubscribe, ReactiveSubscribe } from "./ReactiveSubscribe";
import { defineObservers, isObserver, setObserver } from "./utils";


type ConvertValue<Object extends Record<string, any>> = {
  [Key in keyof Object]: Object[Key] extends Observer<infer Type> ? Type : Object[Key];
}

type PickObverser<Object extends Record<string, any>> = ExtractNever<{
  [Key in keyof Object]: Object[Key] extends Observer<infer Type> ? Type : never;
}>;

export type ReactiveObject<Object extends Record<string, any>>
  = ConvertValue<Object> & ReactiveSubscribe<PickObverser<Object>>;


export function reactive<Object extends Record<string, any>>(
  setup: Readonly<Object> | (() => Readonly<Object>),
): ReactiveObject<Object> {
  const result = isFunction(setup) ? setup() : setup;
  const reactiveObject: Record<string, any> = {};

  defineObservers(reactiveObject);
  keys(result).forEach((name: any) => {
    const value = result[name];
    if (isObserver(value)) {
      setObserver(reactiveObject, name, value);
      Reactive(name)(reactiveObject, name);
    } else {
      reactiveObject[name] = value;
    }
  });

  injectReactiveSubscribe(reactiveObject);
  return reactiveObject as ReactiveObject<Object>;
}
