import type { LogicFlowInstance } from './types';
import type { CallbackArgs, EventArgs, EventCallback, EventEmitter } from '@logicflow/core';
import { tryOnScopeDispose } from '@vueuse/core';

const symbol = Symbol('logicFlow') as InjectionKey<LogicFlowInstance>;

export function provideLogicFlow(lf: LogicFlowInstance) {
  provide(symbol, lf);
}

export function useLogicFlow(): LogicFlowInstance {
  const lf = inject(symbol, null);
  if (!lf) throw new Error('LogicFlow instance is not provided. Please ensure you have called provideLogicFlow before using useLogicFlow.');
  return lf;
}

export function tryLogicFlow(): LogicFlowInstance | null {
  try {
    return useLogicFlow();
  } catch (error) {
    return null;
  }
}

export function useEventListener<T extends keyof EventArgs>(
  emitter: EventEmitter,
  event: T,
  callback: EventCallback<T>,
  predicate?: (event: CallbackArgs<T>) => boolean,
  once?: boolean
): () => void {
  const cleanups: Function[] = [];
  const cleanup = () => {
    cleanups.forEach((fn) => fn());
    cleanups.length = 0;
  };

  const cb: EventCallback<T> = typeof predicate === 'function' ? (event) => (predicate(event) ?? true) && callback(event) : callback;

  emitter.on(event, cb, once);
  cleanups.push(() => emitter.off(event, cb));

  tryOnScopeDispose(cleanup);
  return () => cleanup();
}