import { readFile, stat } from "node:fs/promises";
import { join } from "node:path";
import simpleGit from "simple-git";

export interface GitState {
  branch: string | null;
  gitRemote: string | null;
  lastCommitHash: string | null;
  lastCommitMessage: string | null;
  lastCommitTime: Date | null;
  version: string | null;
}

async function fileExists(p: string): Promise<boolean> {
  try {
    await stat(p);
    return true;
  } catch {
    return false;
  }
}

async function readVersion(repoPath: string): Promise<string | null> {
  const pkgJsonPath = join(repoPath, "package.json");
  if (await fileExists(pkgJsonPath)) {
    try {
      const pkg = JSON.parse(await readFile(pkgJsonPath, "utf8"));
      if (typeof pkg.version === "string") return pkg.version;
    } catch {
      /* ignore */
    }
  }
  const pyProjPath = join(repoPath, "pyproject.toml");
  if (await fileExists(pyProjPath)) {
    const content = await readFile(pyProjPath, "utf8");
    const match = content.match(/^version\s*=\s*"([^"]+)"/m);
    if (match) return match[1];
  }
  return null;
}

export async function readGitState(repoPath: string): Promise<GitState> {
  const isGit = await fileExists(join(repoPath, ".git"));
  if (!isGit) {
    return {
      branch: null,
      gitRemote: null,
      lastCommitHash: null,
      lastCommitMessage: null,
      lastCommitTime: null,
      version: await readVersion(repoPath),
    };
  }
  const git = simpleGit(repoPath);
  const branch = (await git.revparse(["--abbrev-ref", "HEAD"])).trim();
  let gitRemote: string | null = null;
  try {
    gitRemote = (await git.remote(["get-url", "origin"]) || "").toString().trim() || null;
  } catch {
    gitRemote = null;
  }
  const log = await git.log({ maxCount: 1 }).catch(() => null);
  const head = log?.latest ?? null;
  return {
    branch,
    gitRemote,
    lastCommitHash: head?.hash ?? null,
    lastCommitMessage: head?.message ?? null,
    lastCommitTime: head?.date ? new Date(head.date) : null,
    version: await readVersion(repoPath),
  };
}
