import { describe, it, beforeEach, afterEach } from "node:test";
import { expect } from "chai";
import sinon from "sinon";
import { AuthenticatedCommandBuilder, } from "./authenticated-command-builder.js";
import { authenticate } from "../middleware/authentication.js";
import { configure } from "../middleware/user-configuration.js";
import { identify } from "../middleware/user-identification.js";
import setBlocking from "../output.js";
import { YargsChecker } from "../validators/lib.js";
class MockYargs {
    options = {};
    middlewareList = [];
    checkFunction = null;
    option(key, config) {
        this.options[key] = config;
        return this;
    }
    middleware(middlewareArray) {
        this.middlewareList.push(...middlewareArray);
        return this;
    }
    check(fn) {
        this.checkFunction = fn;
        return this;
    }
    getOptions() {
        return this.options;
    }
    getMiddleware() {
        return this.middlewareList;
    }
    getCheckFunction() {
        return this.checkFunction;
    }
}
describe("AuthenticatedCommandBuilder", () => {
    let yargsCheckerStub;
    beforeEach(() => {
        yargsCheckerStub = sinon.stub(YargsChecker.prototype, "check");
    });
    afterEach(() => {
        sinon.restore();
    });
    describe("private constructor", () => {
        it("should only be accessible through static factory methods", () => {
            const builder = AuthenticatedCommandBuilder.create();
            expect(builder).to.be.instanceOf(AuthenticatedCommandBuilder);
        });
    });
    describe("static factory methods", () => {
        describe("create", () => {
            it("should create new instance with provided options", () => {
                const options = {
                    requireSelfHostedEndpoint: true,
                    additionalValidators: [],
                };
                const builder = AuthenticatedCommandBuilder.create(options);
                expect(builder).to.be.instanceOf(AuthenticatedCommandBuilder);
            });
            it("should create new instance with default options when none provided", () => {
                const builder = AuthenticatedCommandBuilder.create();
                expect(builder).to.be.instanceOf(AuthenticatedCommandBuilder);
            });
        });
        describe("withSelfHosted", () => {
            it("should create instance with requireSelfHostedEndpoint set to true", () => {
                const builder = AuthenticatedCommandBuilder.withSelfHosted();
                expect(builder).to.be.instanceOf(AuthenticatedCommandBuilder);
            });
            it("should merge additional options with requireSelfHostedEndpoint", () => {
                const options = { additionalValidators: [] };
                const builder = AuthenticatedCommandBuilder.withSelfHosted(options);
                expect(builder).to.be.instanceOf(AuthenticatedCommandBuilder);
            });
        });
        describe("withMiddleware", () => {
            it("should create instance with additional middleware", () => {
                const mockMiddleware = sinon.stub();
                const builder = AuthenticatedCommandBuilder.withMiddleware([
                    mockMiddleware,
                ]);
                expect(builder).to.be.instanceOf(AuthenticatedCommandBuilder);
            });
            it("should merge additional options with middleware", () => {
                const mockMiddleware = sinon.stub();
                const options = { requireSelfHostedEndpoint: true };
                const builder = AuthenticatedCommandBuilder.withMiddleware([mockMiddleware], options);
                expect(builder).to.be.instanceOf(AuthenticatedCommandBuilder);
            });
        });
    });
    describe("build", () => {
        let mockYargs;
        beforeEach(() => {
            mockYargs = new MockYargs();
            yargsCheckerStub.resolves(true);
        });
        it("should add standard options (api-key and project by default)", () => {
            const builder = AuthenticatedCommandBuilder.create();
            builder.build(mockYargs);
            const options = mockYargs.getOptions();
            expect(options).to.have.property("api-key");
            expect(options).to.have.property("project");
            expect(options).to.not.have.property("self-hosted-endpoint");
        });
        it("should add self-hosted-endpoint option when requireSelfHostedEndpoint is true", () => {
            const builder = AuthenticatedCommandBuilder.create({
                requireSelfHostedEndpoint: true,
            });
            builder.build(mockYargs);
            const options = mockYargs.getOptions();
            expect(options).to.have.property("self-hosted-endpoint");
        });
        it("should apply custom builder function when provided", () => {
            const builder = AuthenticatedCommandBuilder.create();
            const customBuilder = (yargs) => yargs.option("test-option", {
                type: "string",
                describe: "Test option",
            });
            builder.build(mockYargs, customBuilder);
            const options = mockYargs.getOptions();
            expect(options).to.have.property("test-option");
        });
        it("should add all required middleware", () => {
            const builder = AuthenticatedCommandBuilder.create();
            builder.build(mockYargs);
            const middleware = mockYargs.getMiddleware();
            expect(middleware).to.have.length(4);
            expect(middleware).to.include(setBlocking);
            expect(middleware).to.include(authenticate);
            expect(middleware).to.include(configure);
            expect(middleware).to.include(identify);
        });
        it("should add additional middleware when provided", () => {
            const customMiddleware = sinon.stub();
            const builder = AuthenticatedCommandBuilder.withMiddleware([
                customMiddleware,
            ]);
            builder.build(mockYargs);
            const middleware = mockYargs.getMiddleware();
            expect(middleware).to.have.length(5);
            expect(middleware).to.include(customMiddleware);
        });
        it("should always add project validator", () => {
            const builder = AuthenticatedCommandBuilder.create();
            builder.build(mockYargs);
            const checkFunction = mockYargs.getCheckFunction();
            expect(checkFunction).to.not.be.null;
        });
        it("should add additional validators when provided", () => {
            const mockValidator = {
                validate: sinon.stub().resolves({ ok: true }),
            };
            const builder = AuthenticatedCommandBuilder.create({
                additionalValidators: [mockValidator],
            });
            builder.build(mockYargs);
            const checkFunction = mockYargs.getCheckFunction();
            expect(checkFunction).to.not.be.null;
        });
        it("should handle single validator correctly", async () => {
            const builder = AuthenticatedCommandBuilder.create();
            builder.build(mockYargs);
            const checkFunction = mockYargs.getCheckFunction();
            expect(checkFunction).to.not.be.null;
            if (checkFunction) {
                await checkFunction({ project: "test-project" });
                expect(yargsCheckerStub.callCount).to.equal(1);
            }
        });
        it("should handle multiple validators correctly", async () => {
            const mockValidator1 = {
                validate: sinon.stub().resolves({ ok: true }),
            };
            const mockValidator2 = {
                validate: sinon.stub().resolves({ ok: true }),
            };
            const builder = AuthenticatedCommandBuilder.create({
                additionalValidators: [mockValidator1, mockValidator2],
            });
            builder.build(mockYargs);
            const checkFunction = mockYargs.getCheckFunction();
            expect(checkFunction).to.not.be.null;
            if (checkFunction) {
                yargsCheckerStub.onFirstCall().resolves(true);
                yargsCheckerStub.onSecondCall().resolves(true);
                yargsCheckerStub.onThirdCall().resolves(true);
                const result = await checkFunction({ project: "test-project" });
                expect(result).to.be.true;
                expect(yargsCheckerStub.callCount).to.equal(3);
            }
        });
        it("should return early from validation if any validator fails", async () => {
            const mockValidator1 = {
                validate: sinon.stub().resolves({ ok: true }),
            };
            const mockValidator2 = {
                validate: sinon.stub().resolves({ ok: true }),
            };
            const builder = AuthenticatedCommandBuilder.create({
                additionalValidators: [mockValidator1, mockValidator2],
            });
            builder.build(mockYargs);
            const checkFunction = mockYargs.getCheckFunction();
            expect(checkFunction).to.not.be.null;
            if (checkFunction) {
                yargsCheckerStub.onFirstCall().resolves(true);
                yargsCheckerStub.onSecondCall().resolves("Validation failed");
                const result = await checkFunction({ project: "test-project" });
                expect(result).to.equal("Validation failed");
                expect(yargsCheckerStub.callCount).to.equal(2);
            }
        });
    });
    describe("integration scenarios", () => {
        let mockYargs;
        beforeEach(() => {
            mockYargs = new MockYargs();
            yargsCheckerStub.resolves(true);
        });
        it("should build command for basic authenticated scenario", () => {
            const builder = AuthenticatedCommandBuilder.create();
            const result = builder.build(mockYargs);
            const options = mockYargs.getOptions();
            expect(options).to.have.property("api-key");
            expect(options).to.have.property("project");
            expect(result).to.equal(mockYargs);
        });
        it("should build command with self-hosted endpoint support", () => {
            const builder = AuthenticatedCommandBuilder.create({
                requireSelfHostedEndpoint: true,
            });
            builder.build(mockYargs);
            const options = mockYargs.getOptions();
            expect(options).to.have.property("api-key");
            expect(options).to.have.property("project");
            expect(options).to.have.property("self-hosted-endpoint");
        });
        it("should build command with custom options and validation", () => {
            AuthenticatedCommandBuilder.create().build(mockYargs, (yargs) => yargs
                .option("url", {
                type: "string",
                describe: "The URL to process",
            })
                .option("wait", {
                type: "boolean",
                describe: "Wait for completion",
            }));
            const options = mockYargs.getOptions();
            expect(options).to.have.property("url");
            expect(options).to.have.property("wait");
        });
        it("should build command with additional middleware", () => {
            const customMiddleware = sinon.stub();
            const builder = AuthenticatedCommandBuilder.withMiddleware([
                customMiddleware,
            ]);
            builder.build(mockYargs, (yargs) => yargs.option("name", { type: "string", describe: "Project name" }));
            const options = mockYargs.getOptions();
            expect(options).to.have.property("api-key");
            expect(options).to.have.property("project");
            expect(options).to.have.property("name");
            const checkFunction = mockYargs.getCheckFunction();
            expect(checkFunction).to.not.be.null;
        });
    });
});
//# sourceMappingURL=authenticated-command-builder.spec.js.map