import { execFile } from 'child_process';
const tagPattern = /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
function getRemoteTagRefs(repoUrl) {
    return new Promise((resolve, reject) => {
        execFile('git', ['ls-remote', '--tags', '--refs', repoUrl], { encoding: 'utf8' }, (error, stdout, stderr) => {
            if (error) {
                reject(new Error(stderr.trim() || error.message));
                return;
            }
            resolve(stdout);
        });
    });
}
function parseTagRef(line) {
    const [, ref] = line.trim().split(/\s+/);
    const tagRefPrefix = 'refs/tags/';
    if (!ref?.startsWith(tagRefPrefix)) {
        return;
    }
    const tag = ref.slice(tagRefPrefix.length);
    const tagParts = tag.match(tagPattern);
    if (!tagParts) {
        return;
    }
    const [, major, minor, patch, prerelease] = tagParts;
    return {
        tag,
        major: Number(major),
        minor: Number(minor),
        patch: Number(patch),
        prerelease,
    };
}
function comparePrerelease(left, right) {
    if (!left && !right) {
        return 0;
    }
    if (!left) {
        return 1;
    }
    if (!right) {
        return -1;
    }
    const leftParts = left.split('.');
    const rightParts = right.split('.');
    const length = Math.max(leftParts.length, rightParts.length);
    for (let i = 0; i < length; i += 1) {
        const leftPart = leftParts[i];
        const rightPart = rightParts[i];
        if (leftPart === undefined) {
            return -1;
        }
        if (rightPart === undefined) {
            return 1;
        }
        const leftIsNumber = /^\d+$/.test(leftPart);
        const rightIsNumber = /^\d+$/.test(rightPart);
        if (leftIsNumber && rightIsNumber) {
            const numberComparison = Number(leftPart) - Number(rightPart);
            if (numberComparison !== 0) {
                return numberComparison;
            }
            continue;
        }
        if (leftIsNumber) {
            return -1;
        }
        if (rightIsNumber) {
            return 1;
        }
        const stringComparison = leftPart.localeCompare(rightPart);
        if (stringComparison !== 0) {
            return stringComparison;
        }
    }
    return 0;
}
function compareTags(left, right) {
    const versionComparison = left.major - right.major ||
        left.minor - right.minor ||
        left.patch - right.patch;
    return (versionComparison || comparePrerelease(left.prerelease, right.prerelease));
}
const getRepositoryLatestTag = async (repoUrl) => {
    let refs;
    try {
        refs = await getRemoteTagRefs(repoUrl);
    }
    catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        throw new Error(`Unable to read tags from repository ${repoUrl}: ${message}`);
    }
    const usableTags = refs
        .split('\n')
        .map(parseTagRef)
        .filter((tag) => Boolean(tag));
    if (usableTags.length === 0) {
        throw new Error(`No usable SemVer tags were found in repository ${repoUrl}.`);
    }
    const latest = usableTags.reduce((currentLatest, tag) => compareTags(tag, currentLatest) > 0 ? tag : currentLatest);
    return latest.tag;
};
export default getRepositoryLatestTag;
