'use strict';

var rxjs = require('rxjs');
var react = require('react');
var operators = require('rxjs/operators');

// src/internal/use-observable-internal.ts
function useObservableInternal(useCustomEffect, init, inputs) {
  if (!inputs) {
    return react.useState(init)[0];
  }
  const [inputs$] = react.useState(() => new rxjs.BehaviorSubject(inputs));
  const [source$] = react.useState(() => init(inputs$));
  const firstEffectRef = react.useRef(true);
  useCustomEffect(() => {
    if (firstEffectRef.current) {
      firstEffectRef.current = false;
      return;
    }
    inputs$.next(inputs);
  }, inputs);
  return source$;
}
function useObservable(init, inputs) {
  return useObservableInternal(react.useEffect, init, inputs);
}
var identity = (value) => value;
var pluckFirst = (inputs$) => operators.map((input) => input[0])(inputs$);
var pluckCurrentTargetValue = (event$) => operators.map(
  (event) => event.currentTarget.value
)(event$);
var pluckCurrentTargetChecked = (event$) => operators.map(
  (event) => event.currentTarget.checked
)(event$);
var getEmptySubject = () => new rxjs.Subject();
var useRefFn = (init) => {
  const firstRef = react.useRef(true);
  const ref = react.useRef(null);
  if (firstRef.current) {
    firstRef.current = false;
    ref.current = init();
  }
  return ref;
};
var increment = (n) => n + 1 | 0;
var useForceUpdate = () => {
  const updateState = react.useState(0)[1];
  return react.useRef(() => updateState(increment)).current;
};
var useIsomorphicLayoutEffect = /* @__PURE__ */ (() => (
  /* istanbul ignore next */
  typeof window === "undefined" ? react.useEffect : react.useLayoutEffect
))();

// src/use-layout-observable.ts
function useLayoutObservable(init, inputs) {
  return useObservableInternal(useIsomorphicLayoutEffect, init, inputs);
}
function useObservableCallback(init = identity, selector) {
  const [events$] = react.useState(getEmptySubject);
  const [outputs$] = react.useState(() => init(events$));
  const callback = react.useRef((...args) => {
    events$.next(selector ? selector(args) : args[0]);
  }).current;
  return [callback, outputs$];
}
var toObserver = (args) => args[1]?.next ? args[1] : {
  next: args[1],
  error: args[2],
  complete: args[3]
};
function useSubscriptionInternal(useCustomEffect, args) {
  const argsRef = react.useRef(args);
  const observerRef = react.useRef();
  const subscriptionRef = react.useRef();
  useIsomorphicLayoutEffect(() => {
    argsRef.current = args;
    observerRef.current = toObserver(args);
  });
  useCustomEffect(() => {
    const input$ = argsRef.current[0];
    if (!observerRef.current) {
      observerRef.current = toObserver(argsRef.current);
    }
    const subscription = input$.subscribe({
      next: (value) => {
        if (input$ === argsRef.current[0]) {
          observerRef.current.next?.(value);
        }
      },
      error: (error) => {
        if (input$ === argsRef.current[0]) {
          observerRef.current.error ? observerRef.current.error(error) : console.error(error);
        }
      },
      complete: () => {
        if (input$ === argsRef.current[0]) {
          observerRef.current.complete?.();
        }
      }
    });
    subscriptionRef.current = subscription;
    return () => {
      subscription.unsubscribe();
    };
  }, [args[0]]);
  return subscriptionRef;
}

// src/use-subscription.ts
function useSubscription(input$, observerOrNext$, error, complete) {
  return useSubscriptionInternal(react.useEffect, [
    input$,
    observerOrNext$,
    error,
    complete
  ]);
}

// src/use-layout-subscription.ts
function useLayoutSubscription(input$, observerOrNext$, error, complete) {
  return useSubscriptionInternal(useIsomorphicLayoutEffect, [
    input$,
    observerOrNext$,
    error,
    complete
  ]);
}
function useRenderThrow(input$) {
  const forceUpdate = useForceUpdate();
  const errorRef = react.useRef();
  const output$ = useObservable(
    (inputs$) => inputs$.pipe(
      operators.switchMap(([input$2]) => {
        errorRef.current = null;
        return input$2.pipe(
          operators.catchError((error) => {
            errorRef.current = error;
            forceUpdate();
            return rxjs.NEVER;
          })
        );
      })
    ),
    [input$]
  );
  if (errorRef.current) {
    throw errorRef.current;
  }
  return output$;
}
function useObservableStateInternal(useSubscription2, state$OrInit, initialState) {
  if (rxjs.isObservable(state$OrInit)) {
    const state$ = state$OrInit;
    const [state, setState] = react.useState(() => {
      if (state$ instanceof rxjs.BehaviorSubject || state$.value !== void 0) {
        return state$.value;
      }
      if (typeof initialState === "function") {
        return initialState();
      }
      return initialState;
    });
    useSubscription2(state$, setState);
    react.useDebugValue(state);
    return state;
  } else {
    const init = state$OrInit;
    const [state, setState] = react.useState(initialState);
    const [input$] = react.useState(getEmptySubject);
    const [state$] = react.useState(() => init(input$, state));
    const callback = react.useRef((state2) => input$.next(state2)).current;
    useSubscription2(state$, setState);
    react.useDebugValue(state);
    return [state, callback];
  }
}

// src/use-observable-state.ts
function useObservableState(state$OrInit, initialState) {
  return useObservableStateInternal(
    useSubscription,
    state$OrInit,
    initialState
  );
}

// src/use-layout-observable-state.ts
function useLayoutObservableState(state$OrInit, initialState) {
  return useObservableStateInternal(
    useLayoutSubscription,
    state$OrInit,
    initialState
  );
}
function useObservableEagerState(state$) {
  const forceUpdate = useForceUpdate();
  const state$Ref = react.useRef(state$);
  const errorRef = react.useRef();
  const isAsyncEmissionRef = react.useRef(false);
  const didSyncEmit = react.useRef(false);
  const [state, setState] = react.useState(() => {
    let state2;
    state$.subscribe({
      next: (value) => {
        didSyncEmit.current = true;
        state2 = value;
      },
      error: (error) => {
        errorRef.current = error;
      }
    }).unsubscribe();
    return state2;
  });
  useIsomorphicLayoutEffect(() => {
    state$Ref.current = state$;
  });
  react.useEffect(() => {
    errorRef.current = null;
    const input$ = state$Ref.current;
    let secondInitialValue = state;
    const subscription = input$.subscribe({
      next: (value) => {
        if (input$ !== state$Ref.current) {
          return;
        }
        if (isAsyncEmissionRef.current) {
          setState(() => value);
        } else {
          secondInitialValue = value;
        }
      },
      error: (error) => {
        if (input$ !== state$Ref.current) {
          return;
        }
        errorRef.current = error;
        forceUpdate();
      }
    });
    if (!isAsyncEmissionRef.current) {
      if (secondInitialValue !== state) {
        setState(() => secondInitialValue);
      }
    }
    isAsyncEmissionRef.current = true;
    return () => {
      subscription.unsubscribe();
    };
  }, [state$]);
  if (errorRef.current) {
    throw errorRef.current;
  }
  if (didSyncEmit.current) {
    react.useDebugValue(state);
    return state;
  } else {
    throw new Error("Observable did not synchronously emit a value.");
  }
}
function useObservableGetState(state$, initialState, ...path) {
  const value = useObservableState(
    useObservable(
      () => state$.pipe(operators.map((state) => path.reduce(getValue, state)))
    ),
    initialState
  );
  react.useDebugValue(value);
  return value;
}
function getValue(obj, key) {
  return obj[key];
}
function useObservablePickState(state$, initialState, ...keys) {
  const value = useObservableState(
    useObservable(
      () => state$.pipe(
        operators.distinctUntilChanged((s1, s2) => keys.every((k) => s1[k] === s2[k])),
        operators.map(
          (state) => keys.reduce(
            // eslint-disable-next-line no-sequences
            (o, k) => (o[k] = state[k], o),
            {}
          )
        )
      )
    ),
    initialState
  );
  react.useDebugValue(value);
  return value;
}
function useObservableSuspense(resource) {
  const resourceValue = resource.read();
  const forceUpdate = useForceUpdate();
  const [state, setState] = react.useState(resourceValue);
  useSubscription(resource.valueRef$$, (valueRef) => {
    if (valueRef) {
      setState(valueRef.current);
    }
  });
  useSubscription(resource.shouldUpdate$$, forceUpdate);
  react.useDebugValue(state);
  return state;
}
function useObservableRef(initialValue) {
  const [value$] = react.useState(() => new rxjs.BehaviorSubject(initialValue));
  const [ref] = react.useState(() => ({
    get current() {
      return value$.value;
    },
    set current(value) {
      value$.next(value);
    }
  }));
  return [ref, value$];
}
var createHandler = () => {
  const handler = {};
  handler.b = new Promise((resolve) => {
    handler.a = resolve;
  });
  return handler;
};
var ObservableResource = class {
  /**
   * Unlike Promise, Observable is a multiple push mechanism.
   * Only force update when Suspense needs to restart.
   */
  shouldUpdate$$ = new rxjs.Subject();
  get isDestroyed() {
    return this._d;
  }
  valueRef$$ = new rxjs.BehaviorSubject(void 0);
  input$;
  _h = createHandler();
  _e = null;
  _b;
  _d = false;
  _o;
  /**
   * @param input$ An Observable.
   * @param isSuccess A function that determines if the value emitted from
   * `input$` is of success state. If false a Suspense is triggered.
   *  Default all true.
   */
  constructor(input$, isSuccess) {
    this.input$ = input$;
    this._o = {
      next: (value) => {
        this._e = null;
        if (!isSuccess || isSuccess(value)) {
          if (this.valueRef$$.value?.current !== value) {
            this.valueRef$$.next({ current: value });
          }
          if (this._h) {
            const { a: resolve } = this._h;
            this._h = null;
            resolve();
          }
        } else if (!this._h) {
          this._h = createHandler();
          this.shouldUpdate$$.next(true);
        }
      },
      error: (error) => {
        this._e = error;
        if (this._h) {
          const { a: resolve } = this._h;
          this._h = null;
          resolve();
        } else {
          this.shouldUpdate$$.next(true);
        }
      },
      complete: () => {
        if (this._h) {
          this._e = new Error("Suspender ended unexpectedly.");
          const { a: resolve } = this._h;
          this._h = null;
          resolve();
        }
      }
    };
    this._b = input$.subscribe(this._o);
  }
  read() {
    if (this._e) {
      throw this._e;
    }
    if (this._h) {
      throw this._h.b;
    }
    return this.valueRef$$.value?.current;
  }
  reload(newInput$) {
    if (this._d) {
      throw new Error("Cannot reload a destroyed Observable Resource");
    }
    if (newInput$) {
      this.input$ = newInput$;
    }
    this._b.unsubscribe();
    this._e = null;
    if (this._h) {
      this._h.a();
      this._h = createHandler();
    }
    this._b = this.input$.subscribe(this._o);
  }
  destroy() {
    this._d = true;
    this._b.unsubscribe();
    this.shouldUpdate$$.complete();
    if (this._h) {
      this._e = new Error("Resource has been destroyed.");
      const { a: resolve } = this._h;
      this._h = null;
      resolve();
    }
  }
};

exports.ObservableResource = ObservableResource;
exports.identity = identity;
exports.pluckCurrentTargetChecked = pluckCurrentTargetChecked;
exports.pluckCurrentTargetValue = pluckCurrentTargetValue;
exports.pluckFirst = pluckFirst;
exports.useForceUpdate = useForceUpdate;
exports.useLayoutObservable = useLayoutObservable;
exports.useLayoutObservableState = useLayoutObservableState;
exports.useLayoutSubscription = useLayoutSubscription;
exports.useObservable = useObservable;
exports.useObservableCallback = useObservableCallback;
exports.useObservableEagerState = useObservableEagerState;
exports.useObservableGetState = useObservableGetState;
exports.useObservablePickState = useObservablePickState;
exports.useObservableRef = useObservableRef;
exports.useObservableState = useObservableState;
exports.useObservableSuspense = useObservableSuspense;
exports.useRefFn = useRefFn;
exports.useRenderThrow = useRenderThrow;
exports.useSubscription = useSubscription;
