import { getLogger } from "../utils/logger.js";
import { doltHashOf, doltListTags } from "./commit.js";
import { checkoutBranch } from "./branches-api.js";
import { doltListBranches } from "./branch.js";
import { sql } from "drizzle-orm";

//#region src/dolt/ref-helpers.ts
const logger = getLogger("ref-helpers");
const isValidCommitHash = (ref) => {
	return /^[0-9a-v]{32}$/.test(ref);
};
const getProjectScopedRef = (tenantId, projectId, ref) => {
	return `${tenantId}_${projectId}_${ref}`;
};
const getTenantScopedRef = (tenantId, ref) => {
	return `${tenantId}_${ref}`;
};
const resolveRef = (db) => async (ref) => {
	const startTime = Date.now();
	if (isValidCommitHash(ref)) return {
		type: "commit",
		name: ref,
		hash: ref
	};
	const tag = (await doltListTags(db)()).find((t) => t.tag_name === ref);
	if (tag) return {
		type: "tag",
		name: ref,
		hash: tag.tag_hash
	};
	const branchQueryStart = Date.now();
	const branches = await doltListBranches(db)();
	const branchQueryMs = Date.now() - branchQueryStart;
	const branch = branches.find((b) => b.name === ref);
	if (!branch) {
		const totalMs = Date.now() - startTime;
		logger.info({
			ref,
			branchCount: branches.length,
			branchQueryMs,
			totalMs,
			branchNames: branches.map((b) => b.name)
		}, "resolveRef: branch not found in dolt_branches result");
	}
	if (branch) return {
		type: "branch",
		name: ref,
		hash: branch.hash
	};
	return null;
};
const isRefWritable = (resolvedRef) => {
	return resolvedRef.type === "branch";
};
const checkoutRef = (db) => async (resolvedRef) => {
	if (resolvedRef.type === "branch") await checkoutBranch(db)({ branchName: resolvedRef.name });
	else await db.execute(sql.raw(`SELECT DOLT_CHECKOUT('${resolvedRef.hash}')`));
};
const getCurrentBranchOrCommit = (db) => async () => {
	const branch = (await db.execute(sql`SELECT ACTIVE_BRANCH() as branch`)).rows[0]?.branch;
	if (branch) return {
		ref: branch,
		hash: await doltHashOf(db)({ revision: branch }),
		type: "branch"
	};
	const hash = (await db.execute(sql`SELECT DOLT_HASHOF('HEAD') as hash`)).rows[0]?.hash;
	return {
		ref: hash,
		hash,
		type: "commit"
	};
};
const getProjectMainResolvedRef = (db) => async (tenantId, projectId) => {
	const projectMain = `${tenantId}_${projectId}_main`;
	const resolvedRef = await resolveRef(db)(projectMain);
	if (!resolvedRef) throw new Error(`Project main branch not found: ${projectMain}`);
	return resolvedRef;
};
const resolveProjectMainRefs = (db) => async (tenantId, projectIds) => {
	return (await Promise.all(projectIds.map(async (projectId) => {
		const branchName = `${tenantId}_${projectId}_main`;
		const ref = await resolveRef(db)(branchName);
		if (!ref) {
			logger.warn({
				tenantId,
				projectId
			}, "Project main branch not found, skipping");
			return null;
		}
		return {
			projectId,
			ref
		};
	}))).filter((r) => r !== null);
};

//#endregion
export { checkoutRef, getCurrentBranchOrCommit, getProjectMainResolvedRef, getProjectScopedRef, getTenantScopedRef, isRefWritable, isValidCommitHash, resolveProjectMainRefs, resolveRef };