/**
 * BranchManager Port Interface
 *
 * Manages branch-level git operations (create, merge, diff, delete)
 * across project clones. Works directly on branches without requiring
 * a worktree to be checked out.
 */

import type { MergeResult, MergeabilityResult, BranchCommit } from './types.js';

export interface BranchManager {
  /**
   * Ensure a branch exists. Creates it from baseBranch if it doesn't.
   * Idempotent — no-op if the branch already exists.
   */
  ensureBranch(repoPath: string, branch: string, baseBranch: string): Promise<void>;

  /**
   * Merge sourceBranch into targetBranch.
   * Uses an ephemeral worktree for merge safety.
   * Returns conflict info if merge fails.
   */
  mergeBranch(repoPath: string, sourceBranch: string, targetBranch: string): Promise<MergeResult>;

  /**
   * Get the raw unified diff between two branches.
   * Uses three-dot diff (baseBranch...headBranch) to show changes
   * introduced by headBranch since it diverged from baseBranch.
   */
  diffBranches(repoPath: string, baseBranch: string, headBranch: string): Promise<string>;

  /**
   * Delete a branch. No-op if the branch doesn't exist.
   */
  deleteBranch(repoPath: string, branch: string): Promise<void>;

  /**
   * Check if a branch exists in the repository.
   */
  branchExists(repoPath: string, branch: string): Promise<boolean>;

  /**
   * Check if a branch exists as a remote tracking branch (origin/<branch>).
   * Useful for validating branch names against what the remote has,
   * since local branches may not include all remote branches.
   */
  remoteBranchExists(repoPath: string, branch: string): Promise<boolean>;

  /**
   * List commits that headBranch has but baseBranch doesn't.
   * Used for commit-level navigation in code review.
   */
  listCommits(repoPath: string, baseBranch: string, headBranch: string): Promise<BranchCommit[]>;

  /**
   * Get the raw unified diff for a single commit.
   */
  diffCommit(repoPath: string, commitHash: string): Promise<string>;

  /**
   * Get the merge base (common ancestor) of two branches.
   * Returns the commit hash of the merge base.
   */
  getMergeBase(repoPath: string, branch1: string, branch2: string): Promise<string>;

  /**
   * Push a branch to a remote.
   * Defaults to 'origin' if no remote specified.
   */
  pushBranch(repoPath: string, branch: string, remote?: string): Promise<void>;

  /**
   * Dry-run merge check — determines if sourceBranch can be cleanly merged
   * into targetBranch without actually performing the merge.
   * Uses `git merge-tree --write-tree` (git 2.38+).
   */
  checkMergeability(repoPath: string, sourceBranch: string, targetBranch: string): Promise<MergeabilityResult>;

  /**
   * Fetch all refs from a remote.
   * Defaults to 'origin' if no remote specified.
   */
  fetchRemote(repoPath: string, remote?: string): Promise<void>;

  /**
   * Fast-forward a local branch to match its remote-tracking counterpart.
   * No-op if already up to date. Throws if fast-forward is not possible
   * (i.e. the branches have diverged).
   */
  fastForwardBranch(repoPath: string, branch: string, remote?: string): Promise<void>;
}
