"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.sessionPureTransitions = exports.sessionPureSelectors = exports.createSessionStateContainer = exports.TrackedSearchState = exports.SearchSessionState = void 0;
var _uuid = require("uuid");
var _fastDeepEqual = _interopRequireDefault(require("fast-deep-equal"));
var _operators = require("rxjs/operators");
var _public = require("@kbn/kibana-utils-plugin/public");
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */
/**
 * Possible state that current session can be in
 *
 * @public
 */
let SearchSessionState;
/**
 * State of the tracked search
 */
exports.SearchSessionState = SearchSessionState;
(function (SearchSessionState) {
  SearchSessionState["None"] = "none";
  SearchSessionState["Loading"] = "loading";
  SearchSessionState["Completed"] = "completed";
  SearchSessionState["BackgroundLoading"] = "backgroundLoading";
  SearchSessionState["BackgroundCompleted"] = "backgroundCompleted";
  SearchSessionState["Restored"] = "restored";
  SearchSessionState["Canceled"] = "canceled";
})(SearchSessionState || (exports.SearchSessionState = SearchSessionState = {}));
let TrackedSearchState;
exports.TrackedSearchState = TrackedSearchState;
(function (TrackedSearchState) {
  TrackedSearchState["InProgress"] = "inProgress";
  TrackedSearchState["Completed"] = "completed";
  TrackedSearchState["Errored"] = "errored";
})(TrackedSearchState || (exports.TrackedSearchState = TrackedSearchState = {}));
/**
 * Internal state of SessionService
 * {@link SearchSessionState} is inferred from this state
 *
 * @private
 */
const createSessionDefaultState = () => ({
  sessionId: undefined,
  appName: undefined,
  isStored: false,
  isRestore: false,
  isCanceled: false,
  isContinued: false,
  isStarted: false,
  trackedSearches: []
});
const sessionPureTransitions = {
  start: state => ({
    appName
  }) => ({
    ...createSessionDefaultState(),
    sessionId: (0, _uuid.v4)(),
    startTime: new Date(),
    appName
  }),
  restore: state => sessionId => ({
    ...createSessionDefaultState(),
    sessionId,
    isRestore: true,
    isStored: true
  }),
  clear: state => () => createSessionDefaultState(),
  store: state => searchSessionSavedObject => {
    if (!state.sessionId) throw new Error("Can't store session. Missing sessionId");
    if (state.isStored || state.isRestore) throw new Error('Can\'t store because current session is already stored"');
    return {
      ...state,
      isStored: true,
      searchSessionSavedObject
    };
  },
  trackSearch: state => (search, meta = {}) => {
    if (!state.sessionId) throw new Error("Can't track search. Missing sessionId");
    return {
      ...state,
      isStarted: true,
      trackedSearches: state.trackedSearches.concat({
        state: TrackedSearchState.InProgress,
        searchDescriptor: search,
        searchMeta: meta
      }),
      completedTime: undefined
    };
  },
  removeSearch: state => search => {
    const trackedSearches = state.trackedSearches.filter(s => s.searchDescriptor !== search);
    return {
      ...state,
      trackedSearches,
      completedTime: trackedSearches.filter(s => s.state !== TrackedSearchState.InProgress).length === 0 ? new Date() : state.completedTime
    };
  },
  completeSearch: state => search => {
    return {
      ...state,
      trackedSearches: state.trackedSearches.map(s => {
        if (s.searchDescriptor === search) {
          return {
            ...s,
            state: TrackedSearchState.Completed
          };
        }
        return s;
      })
    };
  },
  errorSearch: state => search => {
    return {
      ...state,
      trackedSearches: state.trackedSearches.map(s => {
        if (s.searchDescriptor === search) {
          return {
            ...s,
            state: TrackedSearchState.Errored
          };
        }
        return s;
      })
    };
  },
  updateSearchMeta: state => (search, meta) => {
    return {
      ...state,
      trackedSearches: state.trackedSearches.map(s => {
        if (s.searchDescriptor === search) {
          return {
            ...s,
            searchMeta: {
              ...s.searchMeta,
              ...meta
            }
          };
        }
        return s;
      })
    };
  },
  cancel: state => () => {
    if (!state.sessionId) throw new Error("Can't cancel searches. Missing sessionId");
    if (state.isRestore) throw new Error("Can't cancel searches when restoring older searches");
    return {
      ...state,
      pendingSearches: [],
      isCanceled: true,
      canceledTime: new Date(),
      isStored: false,
      searchSessionSavedObject: undefined
    };
  },
  setSearchSessionSavedObject: state => searchSessionSavedObject => {
    if (!state.sessionId) throw new Error("Can't add search session saved object session into the state. Missing sessionId");
    if (state.sessionId !== searchSessionSavedObject.attributes.sessionId) throw new Error("Can't add search session saved object session into the state. SessionIds don't match.");
    return {
      ...state,
      searchSessionSavedObject
    };
  }
};

/**
 * Consolidate meta info about current seach session
 * Contains both deferred properties and plain properties from state
 */
exports.sessionPureTransitions = sessionPureTransitions;
const sessionPureSelectors = {
  getState: state => () => {
    if (!state.sessionId) return SearchSessionState.None;
    if (!state.isStarted) return SearchSessionState.None;
    if (state.isCanceled) return SearchSessionState.Canceled;
    const pendingSearches = state.trackedSearches.filter(s => s.state === TrackedSearchState.InProgress);
    switch (true) {
      case state.isRestore:
        return pendingSearches.length > 0 ? SearchSessionState.BackgroundLoading : SearchSessionState.Restored;
      case state.isStored:
        return pendingSearches.length > 0 ? SearchSessionState.BackgroundLoading : SearchSessionState.BackgroundCompleted;
      default:
        return pendingSearches.length > 0 ? SearchSessionState.Loading : SearchSessionState.Completed;
    }
    return SearchSessionState.None;
  },
  getMeta(state) {
    const sessionState = this.getState(state)();
    return () => {
      var _state$searchSessionS, _state$searchSessionS2, _state$searchSessionS3;
      return {
        state: sessionState,
        name: (_state$searchSessionS = state.searchSessionSavedObject) === null || _state$searchSessionS === void 0 ? void 0 : _state$searchSessionS.attributes.name,
        startTime: (_state$searchSessionS2 = state.searchSessionSavedObject) !== null && _state$searchSessionS2 !== void 0 && _state$searchSessionS2.attributes.created ? new Date((_state$searchSessionS3 = state.searchSessionSavedObject) === null || _state$searchSessionS3 === void 0 ? void 0 : _state$searchSessionS3.attributes.created) : state.startTime,
        completedTime: state.completedTime,
        canceledTime: state.canceledTime,
        isContinued: state.isContinued
      };
    };
  },
  getSearch(state) {
    return search => {
      var _state$trackedSearche;
      return (_state$trackedSearche = state.trackedSearches.find(s => s.searchDescriptor === search)) !== null && _state$trackedSearche !== void 0 ? _state$trackedSearche : null;
    };
  }
};
exports.sessionPureSelectors = sessionPureSelectors;
const createSessionStateContainer = ({
  freeze = true
} = {
  freeze: true
}) => {
  const stateContainer = (0, _public.createStateContainer)(createSessionDefaultState(), sessionPureTransitions, sessionPureSelectors, freeze ? undefined : {
    freeze: s => s
  });
  const sessionMeta$ = stateContainer.state$.pipe((0, _operators.map)(() => stateContainer.selectors.getMeta()), (0, _operators.distinctUntilChanged)(_fastDeepEqual.default), (0, _operators.shareReplay)(1));
  const sessionState$ = sessionMeta$.pipe((0, _operators.map)(meta => meta.state), (0, _operators.distinctUntilChanged)());
  return {
    stateContainer,
    sessionState$,
    sessionMeta$
  };
};
exports.createSessionStateContainer = createSessionStateContainer;