import { tryOnScopeDispose }          from '@vueuse/core';
import type { MaybeRefOrGetter, Ref } from 'vue';
import type { RouteMeta }             from 'vue-router';


export interface ReactiveRouteOptionsWithTransform<V, R> {
  route?: ReturnType<typeof useRoute>;
  transform?: (val: V) => R;
}

export function useRouteMeta<T extends RouteMeta = RouteMeta, K = T>(
  name: string,
  defaultValue?: MaybeRefOrGetter,
  options: ReactiveRouteOptionsWithTransform<T, K> = {},
): Ref<K> {

  const {
    route = useRoute(),
    transform = value => value as any as K,
  } = options;

  let meta = route.meta[ name ] as any;

  tryOnScopeDispose(() => { meta = undefined; });


  let _trigger: () => void;
  const proxy = customRef<any>((track, trigger) => {
    _trigger = trigger;
    return {
      get() {
        track();
        return transform(meta !== undefined && meta !== '' ? meta : toValue(defaultValue));
      },
      set(v) {
        meta = v;
        trigger();
      },
    };
  });

  watch(
    () => route.meta[ name ],
    (v) => {
      if ( meta === v ) return;
      meta = v;
      _trigger();
    },
    { flush: 'sync' },
  );

  return proxy as Ref<K>;
}
