"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
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 __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.or = exports.and = exports.hasProperty = exports.makeAssertionRec = exports.equalTo = exports.isEmptyString = exports.isFalse = exports.makeAssertionDirect = exports.makeAssertion = exports.isAssertion = exports.Assertion = void 0;
const tracing_1 = __importStar(require("../../Tracing"));
const fileName_1 = "(@effect-ts/system): _src/Testing/Assertion/index.ts";
const L = __importStar(require("../../Collections/Immutable/List"));
const T = __importStar(require("../../Effect"));
const O = __importStar(require("../../Option"));
const ST = __importStar(require("../../Structural"));
const Utils_1 = require("../../Utils");
const AD = __importStar(require("../AssertionData"));
const makeAssertionValue = __importStar(require("../AssertionValue/makeAssertionValue"));
const BA = __importStar(require("../BoolAlgebra"));
const BAM = __importStar(require("../BoolAlgebraM"));
const PR = __importStar(require("../Primitives"));
const R = __importStar(require("../Render"));
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([
    (0, Utils_1.LazyGetter)(),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [])
], Assertion.prototype, "stringify", null);
__decorate([
    (0, Utils_1.LazyGetter)(),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [])
], Assertion.prototype, _a, null);
exports.Assertion = Assertion;
function isAssertion(that) {
    return that instanceof Assertion;
}
exports.isAssertion = isAssertion;
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;
    };
}
exports.makeAssertion = makeAssertion;
function makeAssertionDirect(name, ...params) {
    return (run) => new Assertion(() => R.function_(name, L.of(L.from(params))), run);
}
exports.makeAssertionDirect = makeAssertionDirect;
exports.isFalse = makeAssertion("isFalse")((a) => !a());
exports.isEmptyString = makeAssertion("isEmptyString")((a) => a().length === 0);
function equalTo(expected) {
    return makeAssertion("EqualTo", R.param(expected))((actual) => {
        const actualValue = actual();
        return ST.equals(expected, actualValue);
    });
}
exports.equalTo = equalTo;
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();
        };
    };
}
exports.makeAssertionRec = makeAssertionRec;
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()));
    });
}
exports.hasProperty = hasProperty;
function and(self, that) {
    return new Assertion(() => R.infix(R.param(self), "&&", R.param(that)), (actual) => BA.and_(self.run(actual), that.run(actual)));
}
exports.and = and;
function or(self, that) {
    return new Assertion(() => R.infix(R.param(self), "||", R.param(that)), (actual) => BA.or_(self.run(actual), that.run(actual)));
}
exports.or = or;
//# sourceMappingURL=index.js.map