import { convexToJson, JSONValue, Value } from "@convex-dev/common";
import { GenericDocument, GenericIndexFields } from "../data_model.js";
import {
  IndexRange,
  IndexRangeBuilder,
  LowerBoundIndexRangeBuilder,
  UpperBoundIndexRangeBuilder,
} from "../index_range_builder.js";

export type SerializedRangeExpression = {
  type: "Eq" | "Gt" | "Gte" | "Lt" | "Lte";
  fieldPath: string;
  value: JSONValue;
};

/**
 * @internal
 */
export class IndexRangeBuilderImpl
  extends IndexRange
  implements
    IndexRangeBuilder<GenericDocument, GenericIndexFields>,
    LowerBoundIndexRangeBuilder<GenericDocument, string>,
    UpperBoundIndexRangeBuilder<GenericDocument, string>
{
  private range_expressions: ReadonlyArray<SerializedRangeExpression>;
  private constructor(
    range_expressions: ReadonlyArray<SerializedRangeExpression>
  ) {
    super();
    this.range_expressions = range_expressions;
  }

  static new(): IndexRangeBuilderImpl {
    return new IndexRangeBuilderImpl([]);
  }

  eq(fieldName: string, value: Value) {
    return new IndexRangeBuilderImpl(
      this.range_expressions.concat({
        type: "Eq",
        fieldPath: fieldName,
        value: convexToJson(value),
      })
    );
  }

  gt(fieldName: string, value: Value) {
    return new IndexRangeBuilderImpl(
      this.range_expressions.concat({
        type: "Gt",
        fieldPath: fieldName,
        value: convexToJson(value),
      })
    );
  }
  gte(fieldName: string, value: Value) {
    return new IndexRangeBuilderImpl(
      this.range_expressions.concat({
        type: "Gte",
        fieldPath: fieldName,
        value: convexToJson(value),
      })
    );
  }
  lt(fieldName: string, value: Value) {
    return new IndexRangeBuilderImpl(
      this.range_expressions.concat({
        type: "Lt",
        fieldPath: fieldName,
        value: convexToJson(value),
      })
    );
  }
  lte(fieldName: string, value: Value) {
    return new IndexRangeBuilderImpl(
      this.range_expressions.concat({
        type: "Lte",
        fieldPath: fieldName,
        value: convexToJson(value),
      })
    );
  }

  export() {
    return this.range_expressions;
  }
}
