import { existsSync, readdirSync } from "node:fs";
import path from "node:path";
import { simpleGit } from "simple-git";
import { findTestFiles } from "../../test/test-files.js";
import { CompositeValidator } from "./lib.js";
export class GitBranchOrEnvironmentRequiredError extends Error {
    constructor() {
        super("Invalid arguments: The project directory is not a Git repository, you must specify the `environment` argument or set `--use-git-branch false` to pick one.");
        Object.setPrototypeOf(this, NotAGitRepoError.prototype);
    }
}
export class NotAGitRepoError extends Error {
    constructor() {
        super("Invalid directory: The project directory is not a Git repository.");
        Object.setPrototypeOf(this, NotAGitRepoError.prototype);
    }
}
export class NotAZuploProject extends Error {
    constructor() {
        super("Invalid directory: The project directory is not the root of a Zuplo project.");
        Object.setPrototypeOf(this, NotAZuploProject.prototype);
    }
}
export class ZuploProjectMissingTests extends Error {
    constructor() {
        super("Invalid directory: The project directory does not contain any tests (*.test.ts) in the /tests folder. Create a at least one test of the form some-name.test.ts");
        Object.setPrototypeOf(this, ZuploProjectMissingTests.prototype);
    }
}
export class NoGitCommits extends Error {
    constructor() {
        super("Invalid Git state: The project directory does not contain any commits. Make a commit before deploying.");
        Object.setPrototypeOf(this, NoGitCommits.prototype);
    }
}
export class NotOnAGitBranch extends Error {
    constructor() {
        super("Invalid Git state: You are not on a branch. Run `git checkout -b <branch-name>` to create a new branch.");
        Object.setPrototypeOf(this, NotOnAGitBranch.prototype);
    }
}
export class GitVersionControlValidator {
    async validate(option) {
        const { dir } = option;
        try {
            await simpleGit({ baseDir: dir }).status();
            return { ok: true };
        }
        catch (_err) {
            return {
                ok: false,
                error: new NotAGitRepoError(),
            };
        }
    }
}
export class GitBranchOrEnvironmentValidator {
    async validate(option) {
        const { dir, environment } = option;
        if (typeof environment === "string") {
            return {
                ok: true,
            };
        }
        try {
            if (await simpleGit({ baseDir: dir }).checkIsRepo()) {
                await simpleGit({ baseDir: dir }).status();
                const git = simpleGit({ baseDir: dir });
                const branch = await git.branch();
                if (branch.current) {
                    return {
                        ok: true,
                    };
                }
            }
        }
        catch {
        }
        return {
            ok: false,
            error: new GitBranchOrEnvironmentRequiredError(),
        };
    }
}
export class GitCommitValidator {
    async validate(option) {
        const { dir } = option;
        try {
            const git = simpleGit({ baseDir: dir });
            const commits = await git.log({ maxCount: 1 });
            if (commits.total === 0) {
                return {
                    ok: false,
                    error: new NoGitCommits(),
                };
            }
            return { ok: true };
        }
        catch (_err) {
            return {
                ok: false,
                error: new NoGitCommits(),
            };
        }
    }
}
export class GitBranchValidator {
    async validate(option) {
        const { dir } = option;
        const git = simpleGit({ baseDir: dir });
        const branch = await git.branch();
        if (!branch.current) {
            return {
                ok: false,
                error: new NotOnAGitBranch(),
            };
        }
        return { ok: true };
    }
}
export class ZuploProjectValidator {
    async validate(options) {
        const { dir } = options;
        try {
            const dirPath = path.join(path.normalize(dir), "config");
            if (existsSync(dirPath)) {
                const files = readdirSync(dirPath);
                const existingOASFiles = files.filter((file) => file.endsWith(".oas.json")).length >= 1;
                if (existingOASFiles === true) {
                    return { ok: true };
                }
            }
            return {
                ok: false,
                error: new NotAZuploProject(),
            };
        }
        catch (err) {
            return {
                ok: false,
                error: err,
            };
        }
    }
}
export class ZuploProjectHasTestsValidator {
    async validate(option) {
        const { dir } = option;
        try {
            if (findTestFiles(dir).length >= 1) {
                return { ok: true };
            }
            else {
                return {
                    ok: false,
                    error: new ZuploProjectMissingTests(),
                };
            }
        }
        catch (err) {
            return {
                ok: false,
                error: err,
            };
        }
    }
}
export const validDeployDirectoryValidator = new CompositeValidator(new ZuploProjectValidator(), new GitBranchOrEnvironmentValidator());
export const validTestDirectoryValidator = new CompositeValidator(new ZuploProjectValidator(), new ZuploProjectHasTestsValidator());
//# sourceMappingURL=file-system-validator.js.map