import Docker from "dockerode";
import semver from "semver";
import { $ } from "zx";

import { createTRPCRouter, publicProcedure } from "@/server/api/trpc";

export const dockerRouter = createTRPCRouter({
	list: publicProcedure.query(async () => {
		const docker = new Docker({ socketPath: "/var/run/docker.sock" });
		const containers = await docker.listContainers();

		// curl -fsSL -v "https://quay.io/token?service=quay.io&scope=repository:linuxserver/code-server:pull"
		// curl -fsSL -v -H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" -H "Authorization: Bearer djE6bGludXhzZXJ2ZXIvY29kZS1zZXJ2ZXI6MTc0NTQ1NTk1MTY3NjM5ODA4Mg==" quay.io/v2/linuxserver.io/code-server/tags/list

		// curl -fsSL -v -H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" quay.io/v2/linuxserver.io/code-server/tags/list
		// link: </v2/linuxserver.io/code-server/tags/list?n=100&last=4.18.0-ls180>; rel="next"
		// link: </v2/linuxserver.io/code-server/tags/list?n=100&last=4.90.1-ls217>; rel="next"

		// curl -fsSL -v -H "Accept: application/json" "hub.docker.com/v2/repositories/linuxserver/code-server/tags?n=25&ordering=last_updated"

		return Promise.all(
			containers.map(async (container) => {
				const version = (
					await docker.getImage(container.Image).inspect()
				).RepoTags[0]?.split(":")[1];
				const latest = {
					version: version,
					hash: "N/A",
				};
				if (version && isSemver(version)) {
					latest.version = await getLatestSemverTag(container.Image);
					latest.hash = await getLatestHash(
						`${container.Image.split(":")[0]}:${latest.version}`,
					);
				} else {
					latest.hash = await getLatestHash(container.Image);
				}

				return {
					...container,
					current: {
						version,
						hash: (
							await docker.getImage(container.Image).inspect()
						).RepoDigests[0]
							?.split(":")[1]
							?.substring(0, 12),
					},
					latest,
				};
			}),
		);
	}),
});

function isSemver(tag: string): boolean {
	const removeV = tag.replace(/^v/i, "");
	return !!semver.valid(removeV);
}

async function getLatestSemverTag(image: string): Promise<string> {
	try {
		const allTags =
			await $`bin/regctl tag ls --exclude 'version.*' --exclude 'unstable.*' --exclude '.*rc.*' --exclude 'lib.*' --exclude 'release.*' --exclude 'arm.*
'  --exclude 'amd.*' ${image}`.text();
		const semverTags = allTags
			.split("\n")
			.slice(-20)
			.filter((tag) => isSemver(tag));
		return semver.rsort(semverTags)[0] ?? "Error";
	} catch (ex) {
		return "Error";
	}
}

async function getLatestHash(image: string): Promise<string> {
	try {
		const latestImage = await $`bin/regctl image digest ${image}`.text();
		const latestHash = latestImage.split(":")?.[1];
		return latestHash?.substring(0, 12) ?? "Error";
	} catch (ex) {
		return "Error";
	}
}
