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

export const MatchesSchemaAssertionKind = 'HttpAction#MatchesSchemaAssertion'

/**
 * An assertion that makes sure the input matches a JSON schema. The input has to be
 * a valid JSON string, object, or an array.
 */
export interface IMatchesSchemaAssertion extends IHttpStep {
  kind: typeof MatchesSchemaAssertionKind

  /**
   * The application internal reference to the schema stored in a store.
   */
  ref?: string

  /**
   * When set it ignores the `ref` and uses this JSON schema to validate the input against.
   */
  schema?: unknown
}

/**
 * An assertion that makes sure the input matches a JSON schema. The input has to be
 * a valid JSON string, object, or an array.
 */
export class MatchesSchemaAssertion extends HttpStep {
  override kind = MatchesSchemaAssertionKind

  /**
   * The application internal reference to the schema stored in a store.
   */
  ref?: string

  /**
   * When set it ignores the `ref` and uses this JSON schema to validate the input against.
   */
  schema?: unknown

  static fromRef(ref: string): MatchesSchemaAssertion {
    return new MatchesSchemaAssertion({
      kind: MatchesSchemaAssertionKind,
      enabled: true,
      ref,
    })
  }

  static fromSchema(schema: unknown): MatchesSchemaAssertion {
    return new MatchesSchemaAssertion({
      kind: MatchesSchemaAssertionKind,
      enabled: true,
      schema,
    })
  }

  constructor(init?: IMatchesSchemaAssertion) {
    super()
    if (typeof init === 'object') {
      this.new(init)
    }
  }

  override new(init: IMatchesSchemaAssertion): void {
    super.new(init)
    this.kind = MatchesSchemaAssertionKind
    this.ref = init.ref
    this.schema = init.schema
  }

  checkValidity(): boolean {
    return !!this.schema || !!this.ref
  }

  override toJSON(): IMatchesSchemaAssertion {
    const result: IMatchesSchemaAssertion = {
      ...super.toJSON(),
      kind: MatchesSchemaAssertionKind,
    }
    if (this.ref) {
      result.ref = this.ref
    }
    if (this.schema) {
      result.schema = this.schema
    }
    return result
  }
}
