// =============================================================================
// Pure git API — no ToolContext coupling.
// Requires a GitPushConfig with Gitea credentials for authenticated push.
// =============================================================================

import * as cp from "child_process";
import * as util from "util";
import { PROTECTED_GITEA_REPOS } from "./security";

const execAsync = util.promisify(cp.exec);

import fs from "fs";
import path from "path";

export interface GitPushConfig {
  apiUrl: string;
  apiToken: string;
  username: string;
}

export async function gitCommitAndPush(
  workspaceRoot: string,
  message: string,
  cfg: GitPushConfig,
): Promise<unknown> {
  const cwd = workspaceRoot;
  const { apiUrl, apiToken, username } = cfg;

  try {
    // Check remote URL before committing — block pushes to protected repos
    let remoteCheck = "";
    try {
      remoteCheck = (
        await execAsync("git remote get-url origin", { cwd })
      ).stdout.trim();
    } catch {
      /* no remote yet */
    }

    for (const protectedRepo of PROTECTED_GITEA_REPOS) {
      const repoPath = protectedRepo.replace("mark/", "");
      if (
        remoteCheck.includes(`/${repoPath}`) ||
        remoteCheck.includes(`/${repoPath}.git`)
      ) {
        return {
          error:
            `SECURITY: This workspace is linked to a protected Vibn platform repo (${protectedRepo}). ` +
            `Agents cannot push to platform repos. Only user project repos are writable.`,
        };
      }
    }

    // Write commit message to a temporary file to avoid shell injection
    const msgFile = path.join(cwd, ".git", "COMMIT_EDITMSG");
    fs.writeFileSync(msgFile, message, "utf8");

    await execAsync("git add -A", { cwd });
    await execAsync("git commit -F .git/COMMIT_EDITMSG", { cwd });
    try {
      fs.unlinkSync(msgFile);
    } catch {
      /* ignore */
    }

    // Strip any existing credentials from remote URL and re-inject cleanly
    let remoteUrl = "";
    try {
      remoteUrl = (
        await execAsync("git remote get-url origin", { cwd })
      ).stdout.trim();
    } catch {
      /* no remote */
    }

    const cleanUrl = remoteUrl.replace(/https:\/\/[^@]+@/, "https://");
    const baseUrl = cleanUrl || apiUrl;
    const authedUrl = baseUrl.replace(
      "https://",
      `https://${username}:${apiToken}@`,
    );

    await execAsync(`git remote set-url origin "${authedUrl}"`, { cwd }).catch(
      async () => {
        await execAsync(`git remote add origin "${authedUrl}"`, { cwd });
      },
    );

    const branch = (
      await execAsync("git rev-parse --abbrev-ref HEAD", { cwd })
    ).stdout.trim();
    await execAsync(`git push -u origin "${branch}"`, { cwd, timeout: 60_000 });

    return { success: true, message, branch };
  } catch (err: any) {
    const cleaned = (err.message || "").replace(
      new RegExp(apiToken, "g"),
      "***",
    );
    return { error: `Git operation failed: ${cleaned}` };
  }
}
