import { DataSourceWithBackend, config, getBackendSrv, toDataQueryResponse } from '@grafana/runtime';
import { s as semverExports } from '../_virtual/index.js';
import { getRequestLooper } from './requestLooper.js';
import { of } from '../node_modules/rxjs/dist/esm5/internal/observable/of.js';
import { merge } from '../node_modules/rxjs/dist/esm5/internal/observable/merge.js';
import { map } from '../node_modules/rxjs/dist/esm5/internal/operators/map.js';
import { catchError } from '../node_modules/rxjs/dist/esm5/internal/operators/catchError.js';

var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
const RUNNING_STATUSES = ["started", "submitted", "running"];
const isRunning = (status = "") => RUNNING_STATUSES.includes(status);
const isCustomMeta = (meta) => {
  return !!(typeof meta === "object" && (meta == null ? undefined : meta.hasOwnProperty("queryID")) && (meta == null ? undefined : meta.hasOwnProperty("status")));
};
class DatasourceWithAsyncBackend extends DataSourceWithBackend {
  constructor(instanceSettings) {
    var _a;
    super(instanceSettings);
    __publicField(this, "runningQueries", {});
    __publicField(this, "requestCounter", 100);
    __publicField(this, "requestIdPrefix");
    // cancel sets shouldCancel to tell requestLooper to cancel the query
    __publicField(this, "cancel", (target) => {
      this.storeQuery(target, { shouldCancel: true });
    });
    this.requestIdPrefix = (_a = instanceSettings.uid) != null ? _a : instanceSettings.id;
  }
  query(request) {
    const targets = this.filterQuery ? request.targets.filter(this.filterQuery) : request.targets;
    if (!targets.length) {
      return of({ data: [] });
    }
    const all = [];
    for (let target of targets) {
      if (target.hide) {
        continue;
      }
      all.push(this.doSingle(target, request));
    }
    return merge(...all);
  }
  storeQuery(target, queryInfo) {
    const key = JSON.stringify(target);
    const existingQueryInfo = this.runningQueries[key] || {};
    this.runningQueries[key] = { ...existingQueryInfo, ...queryInfo };
  }
  getQuery(target) {
    const key = JSON.stringify(target);
    return this.runningQueries[key] || {};
  }
  removeQuery(target) {
    const key = JSON.stringify(target);
    delete this.runningQueries[key];
  }
  doSingle(target, request) {
    let queryID = undefined;
    let status = undefined;
    let allData = [];
    return getRequestLooper(
      { ...request, targets: [target], requestId: `${this.requestIdPrefix}_${this.requestCounter++}` },
      {
        /**
         * Additional query to execute if the current query is still in a running state
         */
        getNextQuery: (rsp) => {
          var _a, _b;
          if ((_a = rsp.data) == null ? undefined : _a.length) {
            const first = rsp.data[0];
            const meta = (_b = first.meta) == null ? undefined : _b.custom;
            if (isCustomMeta(meta) && isRunning(meta.status)) {
              queryID = meta.queryID;
              status = meta.status;
              this.storeQuery(target, { queryID });
              return { ...target, queryID };
            }
          }
          this.removeQuery(target);
          return undefined;
        },
        /**
         * The original request
         */
        query: (request2) => {
          const { range, targets, requestId, intervalMs, maxDataPoints } = request2;
          const [_query] = targets;
          const query = {
            ..._query,
            meta: { queryFlow: "async" },
            intervalMs,
            maxDataPoints,
            // getRef optionally chained to support < v8.3.x of Grafana
            datasource: this == null ? undefined : this.getRef(),
            datasourceId: this.id,
            ...this.applyTemplateVariables(_query, request2.scopedVars)
          };
          const cachingDisabled = !config.featureToggles.awsAsyncQueryCaching;
          if (cachingDisabled && isRunning(status)) {
            const requestSkipQueryCacheUnsupported = semverExports.lt(config.buildInfo.version, "10.2.3");
            if (requestSkipQueryCacheUnsupported) {
              return getBackendSrv().fetch({
                method: "POST",
                url: "/api/ds/query",
                headers: { "X-Cache-Skip": true },
                requestId,
                data: {
                  queries: [query],
                  range,
                  from: range.from.valueOf().toString(),
                  to: range.to.valueOf().toString()
                }
              }).pipe(
                map((result) => ({ data: toDataQueryResponse(result).data })),
                catchError((err) => of(toDataQueryResponse(err)))
              );
            }
            return super.query({ ...request2, targets: [query], skipQueryCache: true });
          }
          return super.query({ ...request2, targets: [query] });
        },
        /**
         * Process the results
         */
        process: (data) => {
          for (const frame of data) {
            if (frame.fields.length > 0) {
              allData.push(frame);
            }
          }
          return allData;
        },
        shouldCancel: () => {
          const { shouldCancel } = this.getQuery(target);
          return !!shouldCancel;
        },
        /**
         * Callback that gets executed when unsubscribed
         */
        onCancel: () => {
          if (queryID) {
            this.removeQuery(target);
            this.postResource("cancel", {
              queryId: queryID
            }).catch((err) => {
              err.isHandled = true;
              console.error(`error cancelling query ID: ${queryID}`, err);
            });
          }
        }
      }
    );
  }
}

export { DatasourceWithAsyncBackend };
//# sourceMappingURL=DatasourceWithAsyncBackend.js.map
