import { execSync } from 'child_process';
import { writeFileSync, mkdirSync } from 'fs';
import { tmpdir } from 'os';
import { join } from 'path';

// Askpass helper: git invokes this script (path is what shows up in ps/args),
// and it reads the actual token from an env var — never from argv or the URL.
// This keeps the token out of the process table and out of any git error text.
let _askpassPath = null;
function askpassScript() {
  if (_askpassPath) return _askpassPath;
  const dir = join(tmpdir(), 'agap-mcp-wiki');
  mkdirSync(dir, { recursive: true });
  const scriptPath = join(dir, 'git-askpass.sh');
  writeFileSync(scriptPath, '#!/bin/sh\nprintf %s "$GITEA_ASKPASS_TOKEN"\n', { mode: 0o700 });
  _askpassPath = scriptPath;
  return scriptPath;
}

const BASE = () => process.env.GITEA_URL || 'http://localhost:3000';
let _token = null;

export function initGitea(token) {
  _token = token;
  console.log('Gitea: ready');
}

function token() {
  if (!_token) throw new Error('Gitea not initialized');
  return _token;
}

async function api(path, opts = {}) {
  const res = await fetch(`${BASE()}/api/v1${path}`, {
    ...opts,
    headers: { Authorization: `token ${token()}`, 'Content-Type': 'application/json', ...opts.headers },
  });
  if (!res.ok) throw new Error(`Gitea API ${path}: ${res.status} ${await res.text()}`);
  return res.json();
}

export async function giteaListRepos() {
  return api('/repos/search?limit=50').then(r => r.data.map(r => ({
    name: r.full_name, description: r.description, stars: r.stars_count,
  })));
}

export async function giteaReadFile(repo, path, ref = 'HEAD') {
  const data = await api(`/repos/${repo}/contents/${path}?ref=${ref}`);
  return Buffer.from(data.content, 'base64').toString('utf8');
}

export async function giteaWikiList(repo = 'alvis/AgapHost') {
  const data = await api(`/repos/${repo}/wiki/pages?limit=50`);
  return data.map(p => ({ name: p.title, updated: p.last_commit?.created }));
}

export async function giteaWikiRead(page, repo = 'alvis/AgapHost') {
  const data = await api(`/repos/${repo}/wiki/page/${encodeURIComponent(page)}`);
  return Buffer.from(data.content_base64, 'base64').toString('utf8');
}

export async function giteaWikiWrite(page, content, message, repo = 'alvis/AgapHost') {
  const dir = join(tmpdir(), 'agap-mcp-wiki');
  // Username in the URL is not secret; the password/token is supplied out-of-band
  // via GIT_ASKPASS + GITEA_ASKPASS_TOKEN, so it never appears in the URL, the
  // execSync command string, ps/process args, or surfaced git error output.
  const wikiUrl = `${BASE().replace('http://', 'http://alvis@')}/alvis/AgapHost.wiki.git`;

  const gitEnv = {
    ...process.env,
    GIT_AUTHOR_NAME: 'agap-mcp', GIT_AUTHOR_EMAIL: 'allogn@gmail.com',
    GIT_COMMITTER_NAME: 'agap-mcp', GIT_COMMITTER_EMAIL: 'allogn@gmail.com',
    GIT_ASKPASS: askpassScript(),
    GIT_TERMINAL_PROMPT: '0',
    GITEA_ASKPASS_TOKEN: token(),
  };

  try {
    execSync(`git -C ${dir} pull ${wikiUrl} main`, { env: gitEnv, stdio: 'pipe' });
  } catch {
    execSync(`git clone ${wikiUrl} ${dir}`, { env: gitEnv, stdio: 'pipe' });
  }

  const file = join(dir, `${page}.md`);
  writeFileSync(file, content);
  execSync(`git -C ${dir} add "${page}.md"`, { env: gitEnv, stdio: 'pipe' });
  execSync(`git -C ${dir} commit -m "${message || `Update ${page}`}"`, { env: gitEnv, stdio: 'pipe' });
  execSync(`git -C ${dir} push ${wikiUrl} main`, { env: gitEnv, stdio: 'pipe' });
  return `${page} updated`;
}

export async function giteaListIssues(repo, state = 'open') {
  return api(`/repos/${repo}/issues?state=${state}&type=issues&limit=50`).then(issues =>
    issues.map(i => ({ number: i.number, title: i.title, state: i.state, labels: i.labels.map(l => l.name) }))
  );
}
