import { HttpStep, IHttpStep } from '../../HttpStep.js'

export const EqualAssertionKind = 'HttpAction#EqualAssertion'

/**
 * An assertion that makes sure the input value is [strict] equal to the set value.
 */
export interface IEqualAssertion extends IHttpStep {
  kind: typeof EqualAssertionKind

  /**
   * The value to compare to.
   * This is always a string. Use the `dataType` to determine the correct data type.
   */
  value?: string

  /**
   * The data type of the value. This is a value prefixed with
   * `http://www.w3.org/2001/XMLSchema#` or `http://a.ml/vocabularies/shapes#`.
   *
   * Examples:
   *
   * - `http://www.w3.org/2001/XMLSchema#boolean`
   * - `http://www.w3.org/2001/XMLSchema#string`
   * - `http://www.w3.org/2001/XMLSchema#number`
   * - `http://www.w3.org/2001/XMLSchema#integer`
   * - `http://www.w3.org/2001/XMLSchema#long`
   * - `http://a.ml/vocabularies/shapes#number`
   * - `http://a.ml/vocabularies/shapes#integer`
   * - `http://a.ml/vocabularies/shapes#double`
   * - ...
   *
   * @default `http://www.w3.org/2001/XMLSchema#string`
   */
  dataType?: string

  /**
   * Whether it should check for a value and the data type.
   */
  strict?: boolean
}

/**
 * An assertion that makes sure the input value is [strict] equal to the set value.
 */
export class EqualAssertion extends HttpStep {
  override kind = EqualAssertionKind

  /**
   * The value to compare to.
   * This is always a string. Use the `dataType` to determine the correct data type.
   */
  value?: string

  /**
   * The data type of the value. This is a value prefixed with
   * `http://www.w3.org/2001/XMLSchema#` or `http://a.ml/vocabularies/shapes#`.
   *
   * Examples:
   *
   * - `http://www.w3.org/2001/XMLSchema#boolean`
   * - `http://www.w3.org/2001/XMLSchema#string`
   * - `http://www.w3.org/2001/XMLSchema#number`
   * - `http://www.w3.org/2001/XMLSchema#integer`
   * - `http://www.w3.org/2001/XMLSchema#long`
   * - `http://a.ml/vocabularies/shapes#number`
   * - `http://a.ml/vocabularies/shapes#integer`
   * - `http://a.ml/vocabularies/shapes#double`
   * - ...
   *
   * @default `http://www.w3.org/2001/XMLSchema#string`
   */
  dataType?: string

  /**
   * Whether it should check for a value and the data type.
   */
  strict?: boolean

  constructor(valueOrInit?: IEqualAssertion | string, strict?: boolean, dataType?: string) {
    super()
    if (typeof valueOrInit === 'object') {
      const typed = valueOrInit as IEqualAssertion
      this.new(typed)
    } else if (typeof valueOrInit === 'string') {
      this.new({
        kind: EqualAssertionKind,
        value: valueOrInit,
        dataType,
        strict,
        enabled: true,
      })
    }
  }

  override new(init: IEqualAssertion): void {
    super.new(init)
    this.kind = EqualAssertionKind
    this.value = init.value
    this.dataType = init.dataType
    this.strict = init.strict
  }

  checkValidity(): boolean {
    return !!this.value
  }

  override toJSON(): IEqualAssertion {
    const result: IEqualAssertion = {
      ...super.toJSON(),
      kind: EqualAssertionKind,
    }
    if (this.value) {
      result.value = this.value
    }
    if (this.dataType) {
      result.dataType = this.dataType
    }
    if (typeof this.strict === 'boolean') {
      result.strict = this.strict
    }
    return result
  }
}
