/*
 * Copyright 2025 Palantir Technologies, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { additionalContext } from "../../../Client.js";
import { getWireObjectSet } from "../../../objectSet/createObjectSet.js";
import { BaseListQuery } from "../base-list/BaseListQuery.js";
import { getObjectTypesThatInvalidate } from "../getObjectTypesThatInvalidate.js";
import { OrderBySortingStrategy } from "../sorting/SortingStrategy.js";
export class ObjectSetQuery extends BaseListQuery {
  #baseObjectSetWire;
  #operations;
  #composedObjectSet;
  #objectTypes;
  constructor(store, subject, baseObjectSetWire, operations, cacheKey, opts) {
    super(store, subject, opts, cacheKey, process.env.NODE_ENV !== "production" ? store.client[additionalContext].logger?.child({}, {
      msgPrefix: `ObjectSetQuery<${cacheKey.otherKeys.map(x => JSON.stringify(x)).join(", ")}>`
    }) : undefined);
    this.#baseObjectSetWire = baseObjectSetWire;
    this.#operations = operations;
    this.#composedObjectSet = this.#composeObjectSet(opts);
    this.#objectTypes = this.#extractObjectTypes(opts);
    if (opts.autoFetchMore === true) {
      this.minResultsToLoad = Number.MAX_SAFE_INTEGER;
    } else if (typeof opts.autoFetchMore === "number") {
      this.minResultsToLoad = Math.max(0, opts.autoFetchMore);
    } else {
      this.minResultsToLoad = opts.pageSize || 0;
    }
  }
  #composeObjectSet(opts) {
    let result = opts.baseObjectSet;
    if (opts.withProperties) {
      result = result.withProperties(opts.withProperties);
    }
    if (opts.where) {
      result = result.where(opts.where);
    }
    if (opts.union && opts.union.length > 0) {
      result = result.union(...opts.union);
    }
    if (opts.intersect && opts.intersect.length > 0) {
      result = result.intersect(...opts.intersect);
    }
    if (opts.subtract && opts.subtract.length > 0) {
      result = result.subtract(...opts.subtract);
    }
    if (opts.pivotTo) {
      result = result.pivotTo(opts.pivotTo);
    }
    return result;
  }
  #extractObjectTypes(opts) {
    const types = new Set();
    const baseWire = JSON.parse(this.#baseObjectSetWire);
    if (baseWire.type) {
      types.add(baseWire.type);
    }
    if (opts.union) {
      for (const os of opts.union) {
        const wire = getWireObjectSet(os);
        if (wire.type) {
          types.add(wire.type);
        }
      }
    }
    if (opts.intersect) {
      for (const os of opts.intersect) {
        const wire = getWireObjectSet(os);
        if (wire.type) {
          types.add(wire.type);
        }
      }
    }
    if (opts.subtract) {
      for (const os of opts.subtract) {
        const wire = getWireObjectSet(os);
        if (wire.type) {
          types.add(wire.type);
        }
      }
    }
    return types;
  }

  /**
   * Register changes to the cache specific to ObjectSetQuery
   */
  registerCacheChanges(batch) {
    batch.changes.registerObjectSet(this.cacheKey);
  }

  /**
   * Implements fetchPageData from BaseListQuery template method
   * Fetches a page of data from the composed ObjectSet
   */
  async fetchPageData(signal) {
    if (this.#operations.orderBy && Object.keys(this.#operations.orderBy).length > 0 && !(this.sortingStrategy instanceof OrderBySortingStrategy)) {
      const wireObjectSet = getWireObjectSet(this.#composedObjectSet);
      const {
        resultType
      } = await getObjectTypesThatInvalidate(this.store.client[additionalContext], wireObjectSet);
      this.sortingStrategy = new OrderBySortingStrategy(resultType.apiName, this.#operations.orderBy);
    }

    // Fetch the data with pagination
    const resp = await this.#composedObjectSet.fetchPage({
      $nextPageToken: this.nextPageToken,
      $pageSize: this.options.pageSize,
      // OrderBy is already applied in the composed ObjectSet
      ...(this.#operations.orderBy && Object.keys(this.#operations.orderBy).length > 0 ? {
        $orderBy: this.#operations.orderBy
      } : {})
    });
    if (signal?.aborted) {
      throw new Error("Aborted");
    }
    this.nextPageToken = resp.nextPageToken;
    return resp;
  }
  handleFetchError(error, _status, batch) {
    this.logger?.error("error", error);
    this.store.subjects.get(this.cacheKey).error(error);
    return this.writeToStore({
      data: []
    }, "error", batch);
  }
  registerStreamUpdates(sub) {
    this.createWebsocketSubscription(this.#composedObjectSet, sub, "observeObjectSet");
  }
  invalidateObjectType = async (objectType, changes) => {
    if (this.#objectTypes.has(objectType)) {
      changes?.modified.add(this.cacheKey);
      return this.revalidate(true);
    }
    return Promise.resolve();
  };
  createPayload(params) {
    return {
      resolvedList: params.resolvedData,
      isOptimistic: params.isOptimistic,
      fetchMore: this.fetchMore,
      hasMore: this.nextPageToken != null,
      status: params.status,
      lastUpdated: params.lastUpdated,
      objectSet: this.#composedObjectSet
    };
  }
}
//# sourceMappingURL=ObjectSetQuery.js.map