var __decorate =
  (this && this.__decorate) ||
  function (decorators, target, key, desc) {
    var c = arguments.length,
      r =
        c < 3
          ? target
          : desc === null
          ? (desc = Object.getOwnPropertyDescriptor(target, key))
          : desc,
      d
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
      r = Reflect.decorate(decorators, target, key, desc)
    else
      for (var i = decorators.length - 1; i >= 0; i--)
        if ((d = decorators[i]))
          r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r
    return c > 3 && r && Object.defineProperty(target, key, r), r
  }

var __metadata =
  (this && this.__metadata) ||
  function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
      return Reflect.metadata(k, v)
  }

var _a

import * as tracing_1 from "../../Tracing"
import * as tracing_2 from "../../Tracing"
const fileName_1 = "(@effect-ts/system): _src/Testing/Assertion/index.ts"
import * as L from "../../Collections/Immutable/List"
import * as T from "../../Effect"
import * as O from "../../Option"
import * as ST from "../../Structural"
import { LazyGetter } from "../../Utils"
import * as AD from "../AssertionData"
import * as makeAssertionValue from "../AssertionValue/makeAssertionValue"
import * as BA from "../BoolAlgebra"
import * as BAM from "../BoolAlgebraM"
import * as PR from "../Primitives"
import * as R from "../Render"
export class Assertion {
  constructor(render, run) {
    this.render = render
    this.run = run
    this.runM = this.runM.bind(this)
    this.toString = this.toString.bind(this)
  }

  runM(a) {
    return new BAM.BoolAlgebraM(T.succeed(this.run(a), fileName_1 + ":29:42"))
  }

  get stringify() {
    return this.render().toString()
  }

  toString() {
    return this.stringify
  }

  [(PR._A, ST.equalsSym)](that) {
    if (isAssertion(that)) {
      return this.stringify === that.stringify
    }

    return false
  }

  get [(_a = ST.hashSym)]() {
    return ST.hashString(this.stringify)
  }
}

__decorate(
  [
    LazyGetter(),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [])
  ],
  Assertion.prototype,
  "stringify",
  null
)

__decorate(
  [
    LazyGetter(),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [])
  ],
  Assertion.prototype,
  _a,
  null
)

export function isAssertion(that) {
  return that instanceof Assertion
}
export function makeAssertion(name, ...params) {
  return (run) => {
    const assertion = makeAssertionDirect(
      name,
      ...params
    )((actual) => {
      const actualValue = actual()

      const result = () =>
        run(() => actualValue)
          ? BA.success(
              makeAssertionValue.makeAssertionValue(
                assertion,
                () => actualValue,
                result
              )
            )
          : BA.failure(
              makeAssertionValue.makeAssertionValue(
                assertion,
                () => actualValue,
                result
              )
            )

      return result()
    })
    return assertion
  }
}
export function makeAssertionDirect(name, ...params) {
  return (run) => new Assertion(() => R.function_(name, L.of(L.from(params))), run)
}
export const isFalse = /*#__PURE__*/ makeAssertion("isFalse")((a) => !a())
export const isEmptyString = /*#__PURE__*/ makeAssertion("isEmptyString")(
  (a) => a().length === 0
)
export function equalTo(expected) {
  return makeAssertion(
    "EqualTo",
    R.param(expected)
  )((actual) => {
    const actualValue = actual()
    return ST.equals(expected, actualValue)
  })
}
export function makeAssertionRec(name, ...params) {
  return (assertion) => {
    return (get, orElse = AD.asFailure) => {
      const resultAssertion = () =>
        makeAssertionDirect(
          name,
          ...params
        )((a) => {
          const actualValue = a()
          return O.fold_(
            get(a),
            () => orElse(AD.makeAssertionData(resultAssertion(), actualValue)),
            (b) => {
              const innerResult = assertion.run(() => b)

              const result = () =>
                BA.isSuccess(innerResult)
                  ? BA.success(
                      makeAssertionValue.makeAssertionValue(
                        resultAssertion(),
                        () => actualValue,
                        result
                      )
                    )
                  : BA.failure(
                      makeAssertionValue.makeAssertionValue(
                        resultAssertion(),
                        () => b,
                        () => innerResult
                      )
                    )

              return result()
            }
          )
        })

      return resultAssertion()
    }
  }
}
export function hasProperty(name, proj, assertion) {
  return makeAssertionRec(
    "hasField",
    R.param(R.quoted(name)),
    R.param(R.field(name)),
    R.param(assertion)
  )(assertion)((actual) => {
    return O.some(proj(actual()))
  })
}
export function and(self, that) {
  return new Assertion(
    () => R.infix(R.param(self), "&&", R.param(that)),
    (actual) => BA.and_(self.run(actual), that.run(actual))
  )
}
export function or(self, that) {
  return new Assertion(
    () => R.infix(R.param(self), "||", R.param(that)),
    (actual) => BA.or_(self.run(actual), that.run(actual))
  )
}
//# sourceMappingURL=index.js.map
