'use strict';
// Parent-branch ahead/behind display.
//
// Reports `{ branch, parent, ahead, behind, diffLines }` for a given cwd.
// The "parent" is resolved in this order:
//   1. <repo>/.claude/worktrees.json → worktreeConfig[branch].parent (ccmanager-compatible)
//   2. git config branch.<current>.merge (typical for tracking branches)
//   3. heuristic: main, then master, then develop, then origin/HEAD
//
// Results are cached per-cwd with a 30s TTL to avoid forking git on every
// tab render; callers pass {force: true} to bypass the cache.

const { execFile } = require('child_process');
const fs = require('fs');
const path = require('path');

const _cache = new Map(); // cwd -> { at, data }
const TTL_MS = 30_000;

function _git(cwd, args, timeoutMs = 3000) {
  return new Promise((resolve) => {
    execFile('git', args, { cwd, timeout: timeoutMs, windowsHide: true }, (err, stdout, stderr) => {
      if (err) { resolve(null); return; }
      resolve(String(stdout || '').trim());
    });
  });
}

async function _currentBranch(cwd) {
  return (await _git(cwd, ['rev-parse', '--abbrev-ref', 'HEAD'])) || '';
}

async function _repoRoot(cwd) {
  return (await _git(cwd, ['rev-parse', '--show-toplevel'])) || '';
}

function _readWorktreeConfig(repoRoot) {
  if (!repoRoot) return null;
  const p = path.join(repoRoot, '.claude', 'worktrees.json');
  try {
    const raw = fs.readFileSync(p, 'utf8');
    const data = JSON.parse(raw);
    if (data && typeof data === 'object' && data.worktrees && typeof data.worktrees === 'object') {
      return data.worktrees;
    }
    return null;
  } catch { return null; }
}

async function _resolveParent(cwd, branch) {
  const repoRoot = await _repoRoot(cwd);
  if (!repoRoot || !branch) return null;

  // 1. worktreeConfig override
  const wc = _readWorktreeConfig(repoRoot);
  if (wc && wc[branch] && typeof wc[branch].parent === 'string') {
    return wc[branch].parent;
  }

  // 2. tracking branch from git config
  const tracking = await _git(cwd, ['rev-parse', '--abbrev-ref', `${branch}@{upstream}`]);
  if (tracking && !tracking.startsWith('fatal')) {
    // Don't use the upstream of the branch itself as "parent" if upstream is
    // the same branch on a remote (origin/<branch>). That's a push target,
    // not an integration parent.
    if (tracking !== `origin/${branch}`) return tracking;
  }

  // 3. heuristic: main, master, develop, origin/HEAD
  for (const candidate of ['main', 'master', 'develop']) {
    const shown = await _git(cwd, ['rev-parse', '--verify', '--quiet', candidate]);
    if (shown) return candidate;
  }
  const originHead = await _git(cwd, ['symbolic-ref', '--quiet', '--short', 'refs/remotes/origin/HEAD']);
  if (originHead) return originHead;

  return null;
}

// Get ahead/behind vs parent. Returns:
//   { branch, parent, ahead, behind, diffLines: {added, removed} }
// or null if not in a git repo.
async function getGitStatus(cwd, { force = false } = {}) {
  if (!cwd) return null;
  if (!force) {
    const cached = _cache.get(cwd);
    if (cached && Date.now() - cached.at < TTL_MS) return cached.data;
  }
  const branch = await _currentBranch(cwd);
  if (!branch || branch === 'HEAD') {
    const empty = { branch: '', parent: null, ahead: 0, behind: 0, diffLines: { added: 0, removed: 0 } };
    _cache.set(cwd, { at: Date.now(), data: empty });
    return empty;
  }

  const parent = await _resolveParent(cwd, branch);
  let ahead = 0;
  let behind = 0;
  if (parent) {
    const revlist = await _git(cwd, ['rev-list', '--left-right', '--count', `${parent}...${branch}`]);
    if (revlist) {
      // stdout format: "behind\tahead"  (left = parent, right = branch).
      const parts = revlist.split(/\s+/).filter(Boolean);
      if (parts.length >= 2) {
        behind = parseInt(parts[0], 10) || 0;
        ahead = parseInt(parts[1], 10) || 0;
      }
    }
  }

  // Uncommitted diff counts (working-tree vs HEAD)
  let added = 0, removed = 0;
  const numstat = await _git(cwd, ['diff', '--numstat', 'HEAD']);
  if (numstat) {
    for (const line of numstat.split('\n')) {
      const m = line.match(/^(\d+|-)\s+(\d+|-)/);
      if (!m) continue;
      added += (m[1] === '-' ? 0 : parseInt(m[1], 10));
      removed += (m[2] === '-' ? 0 : parseInt(m[2], 10));
    }
  }

  const data = { branch, parent, ahead, behind, diffLines: { added, removed } };
  _cache.set(cwd, { at: Date.now(), data });
  return data;
}

function _clearCache() { _cache.clear(); }

module.exports = { getGitStatus, _clearCache, TTL_MS };
