/** @internal */
export interface Breakpoint {
  /** @internal */
  line: number;
}

/** @internal */
export interface ProgramState {
  /**
   * Global variables provided by the profile.
   *
   * @internal
   */
  profile: Map<string, DebugValue | null>;
  /**
   * Script variables declared in the global scope. Profile and standard library objects are not included.
   *
   * Uninitialized variables are represented as `null`. A variable with a `null` value will have that value represented
   * as a `DebugValue` with `value: null`.
   *
   * @internal
   */
  globals: Map<string, DebugValue | null>;
  /**
   * Function parameters and variables declared in the function body. Only defined when the program is paused in a
   * function. Otherwise there is no local state.
   *
   * Uninitialized variables are represented as `null`. A variable with a `null` value will have that value represented
   * as a `DebugValue` with `value: null`.
   *
   * @internal
   */
  locals?: Map<string, DebugValue | null> | null;
}

/** @internal */
export interface Debugger {
  /**
   * @param at - the breakpoint that the script is paused on.
   * @param state - current program state.
   * @returns a promise that, when resolved, will allow the script to resume.
   * @internal
   */
  pause(at: Breakpoint, state: ProgramState): Promise<void>;
}

/** @internal */
export interface BaseDebugValue {
  /**
   * `TypeOf()` type name
   *
   * @internal
   */
  arcadeType: string;
  /**
   * `true` if mutable, `false` if immutable, `undefined` if not relevant for the type.
   *
   * @internal
   */
  mutable?: boolean | null;
}

/** @internal */
export interface MinimalDebugValue extends BaseDebugValue {
  /** @internal */
  type: "minimal";
}

/** @internal */
export interface PrimitiveDebugValue extends BaseDebugValue {
  /** @internal */
  type: "primitive";
  /** @internal */
  value: string | number | boolean | null;
}

/** @internal */
export interface SimpleDebugValue extends BaseDebugValue {
  /** @internal */
  type: "simple";
  /** @internal */
  render(): string;
}

/** @internal */
export interface SequenceContainerDebugValue extends BaseDebugValue {
  /** @internal */
  type: "sequence-container";
  /** @internal */
  length: number;
  /** @internal */
  expand(): DebugValue[];
}

/** @internal */
export interface AssociativeContainerDebugValue extends BaseDebugValue {
  /** @internal */
  type: "associative-container";
  /** @internal */
  expand(): Map<string, DebugValue>;
}

/** @internal */
export interface FeatureSetDebugValue extends BaseDebugValue {
  /** @internal */
  type: "feature-set";
  /**
   * Wrapped `Schema()`.
   *
   * @internal
   */
  schema(): Promise<DebugValue>;
  /**
   * Query an arbitrary batch of the features in this feature set. The size and order is unspecified but for example an
   * implementation may fetch the first 100 features from a service. The result features should include all available
   * fields and list them in display order in the `fields` property. The returned `features` are wrapped arcade features
   * which each include values for all returned `fields` in their
   * [expand()](https://developers.arcgis.com/javascript/latest/references/core/arcade/debug/#AssociativeContainerDebugValue-expand) result.
   *
   * @param abortSignal
   * @internal
   */
  querySample?(abortSignal?: AbortSignal): Promise<{
      fields: string[];
      features: AssociativeContainerDebugValue[];
  }>;
}

/** @internal */
export interface FeatureSetCollectionItem {
  /** @internal */
  id: string;
  /** @internal */
  name?: string | null;
  /** @internal */
  featureSet: FeatureSetDebugValue;
}

/** @internal */
export interface FeatureSetCollectionDebugValue extends BaseDebugValue {
  /** @internal */
  type: "feature-set-collection";
  /** @internal */
  load(): Promise<FeatureSetCollectionItem[]>;
}

/** @internal */
export type DebugValue = MinimalDebugValue | PrimitiveDebugValue | SimpleDebugValue | SequenceContainerDebugValue | AssociativeContainerDebugValue | FeatureSetDebugValue | FeatureSetCollectionDebugValue;