package cmd

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/spf13/cobra"
	"github.com/steveyegge/gastown/internal/beads"
	"github.com/steveyegge/gastown/internal/config"
	"github.com/steveyegge/gastown/internal/git"
	"github.com/steveyegge/gastown/internal/style"
	"github.com/steveyegge/gastown/internal/workspace"
)

// Integration branch template constants
const defaultIntegrationBranchTemplate = "integration/{epic}"

// invalidBranchCharsRegex matches characters that are invalid in git branch names.
// Git branch names cannot contain: ~ ^ : \ space, .., @{, or end with .lock
var invalidBranchCharsRegex = regexp.MustCompile(`[~^:\s\\]|\.\.|\.\.|@\{`)

// buildIntegrationBranchName expands an integration branch template with variables.
// Variables supported:
//   - {epic}: Full epic ID (e.g., "RA-123")
//   - {prefix}: Epic prefix before first hyphen (e.g., "RA")
//   - {user}: Git user.name (e.g., "klauern")
//
// If template is empty, uses defaultIntegrationBranchTemplate.
func buildIntegrationBranchName(template, epicID string) string {
	if template == "" {
		template = defaultIntegrationBranchTemplate
	}

	result := template
	result = strings.ReplaceAll(result, "{epic}", epicID)
	result = strings.ReplaceAll(result, "{prefix}", extractEpicPrefix(epicID))

	// Git user (optional - leaves placeholder if not available)
	if user := getGitUserName(); user != "" {
		result = strings.ReplaceAll(result, "{user}", user)
	}

	return result
}

// extractEpicPrefix extracts the prefix from an epic ID (before the first hyphen).
// Examples: "RA-123" -> "RA", "PROJ-456" -> "PROJ", "abc" -> "abc"
func extractEpicPrefix(epicID string) string {
	if idx := strings.Index(epicID, "-"); idx > 0 {
		return epicID[:idx]
	}
	return epicID
}

// getGitUserName returns the git user.name config value, or empty if not set.
func getGitUserName() string {
	cmd := exec.Command("git", "config", "user.name")
	out, err := cmd.Output()
	if err != nil {
		return ""
	}
	return strings.TrimSpace(string(out))
}

// validateBranchName checks if a branch name is valid for git.
// Returns an error if the branch name contains invalid characters.
func validateBranchName(branchName string) error {
	if branchName == "" {
		return fmt.Errorf("branch name cannot be empty")
	}

	// Check for invalid characters
	if invalidBranchCharsRegex.MatchString(branchName) {
		return fmt.Errorf("branch name %q contains invalid characters (~ ^ : \\ space, .., or @{)", branchName)
	}

	// Check for .lock suffix
	if strings.HasSuffix(branchName, ".lock") {
		return fmt.Errorf("branch name %q cannot end with .lock", branchName)
	}

	// Check for leading/trailing slashes or dots
	if strings.HasPrefix(branchName, "/") || strings.HasSuffix(branchName, "/") {
		return fmt.Errorf("branch name %q cannot start or end with /", branchName)
	}
	if strings.HasPrefix(branchName, ".") || strings.HasSuffix(branchName, ".") {
		return fmt.Errorf("branch name %q cannot start or end with .", branchName)
	}

	// Check for consecutive slashes
	if strings.Contains(branchName, "//") {
		return fmt.Errorf("branch name %q cannot contain consecutive slashes", branchName)
	}

	return nil
}

// getIntegrationBranchField extracts the integration_branch field from an epic's description.
// Returns empty string if the field is not found.
func getIntegrationBranchField(description string) string {
	if description == "" {
		return ""
	}

	lines := strings.Split(description, "\n")
	for _, line := range lines {
		trimmed := strings.TrimSpace(line)
		if strings.HasPrefix(strings.ToLower(trimmed), "integration_branch:") {
			value := strings.TrimPrefix(trimmed, "integration_branch:")
			value = strings.TrimPrefix(value, "Integration_branch:")
			value = strings.TrimPrefix(value, "INTEGRATION_BRANCH:")
			// Handle case variations
			for _, prefix := range []string{"integration_branch:", "Integration_branch:", "INTEGRATION_BRANCH:"} {
				if strings.HasPrefix(trimmed, prefix) {
					value = strings.TrimPrefix(trimmed, prefix)
					break
				}
			}
			// Re-parse properly - the prefix removal above is messy
			parts := strings.SplitN(trimmed, ":", 2)
			if len(parts) == 2 {
				return strings.TrimSpace(parts[1])
			}
		}
	}
	return ""
}

// getIntegrationBranchTemplate returns the integration branch template to use.
// Priority: CLI flag > rig config > default
func getIntegrationBranchTemplate(rigPath, cliOverride string) string {
	if cliOverride != "" {
		return cliOverride
	}

	// Try to load rig settings
	settingsPath := filepath.Join(rigPath, "settings", "config.json")
	settings, err := config.LoadRigSettings(settingsPath)
	if err != nil {
		return defaultIntegrationBranchTemplate
	}

	if settings.MergeQueue != nil && settings.MergeQueue.IntegrationBranchTemplate != "" {
		return settings.MergeQueue.IntegrationBranchTemplate
	}

	return defaultIntegrationBranchTemplate
}

// IntegrationStatusOutput is the JSON output structure for integration status.
type IntegrationStatusOutput struct {
	Epic        string                       `json:"epic"`
	Branch      string                       `json:"branch"`
	Created     string                       `json:"created,omitempty"`
	AheadOfMain int                          `json:"ahead_of_main"`
	MergedMRs   []IntegrationStatusMRSummary `json:"merged_mrs"`
	PendingMRs  []IntegrationStatusMRSummary `json:"pending_mrs"`
}

// IntegrationStatusMRSummary represents a merge request in the integration status output.
type IntegrationStatusMRSummary struct {
	ID     string `json:"id"`
	Title  string `json:"title"`
	Status string `json:"status,omitempty"`
}

// runMqIntegrationCreate creates an integration branch for an epic.
func runMqIntegrationCreate(cmd *cobra.Command, args []string) error {
	epicID := args[0]

	// Find workspace
	townRoot, err := workspace.FindFromCwdOrError()
	if err != nil {
		return fmt.Errorf("not in a Gas Town workspace: %w", err)
	}

	// Find current rig
	_, r, err := findCurrentRig(townRoot)
	if err != nil {
		return err
	}

	// Initialize beads for the rig
	bd := beads.New(r.Path)

	// 1. Verify epic exists
	epic, err := bd.Show(epicID)
	if err != nil {
		if err == beads.ErrNotFound {
			return fmt.Errorf("epic '%s' not found", epicID)
		}
		return fmt.Errorf("fetching epic: %w", err)
	}

	// Verify it's actually an epic
	if epic.Type != "epic" {
		return fmt.Errorf("'%s' is a %s, not an epic", epicID, epic.Type)
	}

	// Build integration branch name from template
	template := getIntegrationBranchTemplate(r.Path, mqIntegrationCreateBranch)
	branchName := buildIntegrationBranchName(template, epicID)

	// Validate the branch name
	if err := validateBranchName(branchName); err != nil {
		return fmt.Errorf("invalid branch name: %w", err)
	}

	// Initialize git for the rig
	g := git.NewGit(r.Path)

	// Check if integration branch already exists locally
	exists, err := g.BranchExists(branchName)
	if err != nil {
		return fmt.Errorf("checking branch existence: %w", err)
	}
	if exists {
		return fmt.Errorf("integration branch '%s' already exists locally", branchName)
	}

	// Check if branch exists on remote
	remoteExists, err := g.RemoteBranchExists("origin", branchName)
	if err != nil {
		// Log warning but continue - remote check isn't critical
		fmt.Printf("  %s\n", style.Dim.Render("(could not check remote, continuing)"))
	}
	if remoteExists {
		return fmt.Errorf("integration branch '%s' already exists on origin", branchName)
	}

	// Ensure we have latest main
	fmt.Printf("Fetching latest from origin...\n")
	if err := g.Fetch("origin"); err != nil {
		return fmt.Errorf("fetching from origin: %w", err)
	}

	// 2. Create branch from origin/main
	fmt.Printf("Creating branch '%s' from main...\n", branchName)
	if err := g.CreateBranchFrom(branchName, "origin/main"); err != nil {
		return fmt.Errorf("creating branch: %w", err)
	}

	// 3. Push to origin
	fmt.Printf("Pushing to origin...\n")
	if err := g.Push("origin", branchName, false); err != nil {
		// Clean up local branch on push failure (best-effort cleanup)
		_ = g.DeleteBranch(branchName, true)
		return fmt.Errorf("pushing to origin: %w", err)
	}

	// 4. Store integration branch info in epic metadata
	// Update the epic's description to include the integration branch info
	newDesc := addIntegrationBranchField(epic.Description, branchName)
	if newDesc != epic.Description {
		if err := bd.Update(epicID, beads.UpdateOptions{Description: &newDesc}); err != nil {
			// Non-fatal - branch was created, just metadata update failed
			fmt.Printf("  %s\n", style.Dim.Render("(warning: could not update epic metadata)"))
		}
	}

	// Success output
	fmt.Printf("\n%s Created integration branch\n", style.Bold.Render("✓"))
	fmt.Printf("  Epic:   %s\n", epicID)
	fmt.Printf("  Branch: %s\n", branchName)
	fmt.Printf("  From:   main\n")
	fmt.Printf("\n  Future MRs for this epic's children can target:\n")
	fmt.Printf("    gt mq submit --epic %s\n", epicID)

	return nil
}

// addIntegrationBranchField adds or updates the integration_branch field in a description.
func addIntegrationBranchField(description, branchName string) string {
	fieldLine := "integration_branch: " + branchName

	// If description is empty, just return the field
	if description == "" {
		return fieldLine
	}

	// Check if integration_branch field already exists
	lines := strings.Split(description, "\n")
	var newLines []string
	found := false

	for _, line := range lines {
		trimmed := strings.TrimSpace(line)
		if strings.HasPrefix(strings.ToLower(trimmed), "integration_branch:") {
			// Replace existing field
			newLines = append(newLines, fieldLine)
			found = true
		} else {
			newLines = append(newLines, line)
		}
	}

	if !found {
		// Add field at the beginning
		newLines = append([]string{fieldLine}, newLines...)
	}

	return strings.Join(newLines, "\n")
}

// runMqIntegrationLand merges an integration branch to main.
func runMqIntegrationLand(cmd *cobra.Command, args []string) error {
	epicID := args[0]

	// Find workspace
	townRoot, err := workspace.FindFromCwdOrError()
	if err != nil {
		return fmt.Errorf("not in a Gas Town workspace: %w", err)
	}

	// Find current rig
	_, r, err := findCurrentRig(townRoot)
	if err != nil {
		return err
	}

	// Initialize beads and git for the rig
	bd := beads.New(r.Path)
	g := git.NewGit(r.Path)

	// Show what we're about to do
	if mqIntegrationLandDryRun {
		fmt.Printf("%s Dry run - no changes will be made\n\n", style.Bold.Render("🔍"))
	}

	// 1. Verify epic exists
	epic, err := bd.Show(epicID)
	if err != nil {
		if err == beads.ErrNotFound {
			return fmt.Errorf("epic '%s' not found", epicID)
		}
		return fmt.Errorf("fetching epic: %w", err)
	}

	if epic.Type != "epic" {
		return fmt.Errorf("'%s' is a %s, not an epic", epicID, epic.Type)
	}

	// Get integration branch name from epic metadata (stored at create time)
	// Fall back to default template for backward compatibility with old epics
	branchName := getIntegrationBranchField(epic.Description)
	if branchName == "" {
		branchName = buildIntegrationBranchName(defaultIntegrationBranchTemplate, epicID)
	}

	fmt.Printf("Landing integration branch for epic: %s\n", epicID)
	fmt.Printf("  Title: %s\n\n", epic.Title)

	// 2. Verify integration branch exists
	fmt.Printf("Checking integration branch...\n")
	exists, err := g.BranchExists(branchName)
	if err != nil {
		return fmt.Errorf("checking branch existence: %w", err)
	}

	// Also check remote if local doesn't exist
	if !exists {
		remoteExists, err := g.RemoteBranchExists("origin", branchName)
		if err != nil {
			return fmt.Errorf("checking remote branch: %w", err)
		}
		if !remoteExists {
			return fmt.Errorf("integration branch '%s' does not exist (locally or on origin)", branchName)
		}
		// Fetch and create local tracking branch
		fmt.Printf("Fetching integration branch from origin...\n")
		if err := g.FetchBranch("origin", branchName); err != nil {
			return fmt.Errorf("fetching branch: %w", err)
		}
	}
	fmt.Printf("  %s Branch exists\n", style.Bold.Render("✓"))

	// 3. Verify all MRs targeting this integration branch are merged
	fmt.Printf("Checking open merge requests...\n")
	openMRs, err := findOpenMRsForIntegration(bd, branchName)
	if err != nil {
		return fmt.Errorf("checking open MRs: %w", err)
	}

	if len(openMRs) > 0 {
		fmt.Printf("\n  %s Open merge requests targeting %s:\n", style.Bold.Render("⚠"), branchName)
		for _, mr := range openMRs {
			fmt.Printf("    - %s: %s\n", mr.ID, mr.Title)
		}
		fmt.Println()

		if !mqIntegrationLandForce {
			return fmt.Errorf("cannot land: %d open MRs (use --force to override)", len(openMRs))
		}
		fmt.Printf("  %s Proceeding anyway (--force)\n", style.Dim.Render("⚠"))
	} else {
		fmt.Printf("  %s No open MRs targeting integration branch\n", style.Bold.Render("✓"))
	}

	// Dry run stops here
	if mqIntegrationLandDryRun {
		fmt.Printf("\n%s Dry run complete. Would perform:\n", style.Bold.Render("🔍"))
		fmt.Printf("  1. Merge %s to main (--no-ff)\n", branchName)
		if !mqIntegrationLandSkipTests {
			fmt.Printf("  2. Run tests on main\n")
		}
		fmt.Printf("  3. Push main to origin\n")
		fmt.Printf("  4. Delete integration branch (local and remote)\n")
		fmt.Printf("  5. Update epic status to closed\n")
		return nil
	}

	// Ensure working directory is clean
	status, err := g.Status()
	if err != nil {
		return fmt.Errorf("checking git status: %w", err)
	}
	if !status.Clean {
		return fmt.Errorf("working directory is not clean; please commit or stash changes")
	}

	// Fetch latest
	fmt.Printf("Fetching latest from origin...\n")
	if err := g.Fetch("origin"); err != nil {
		return fmt.Errorf("fetching from origin: %w", err)
	}

	// 4. Checkout main and merge integration branch
	fmt.Printf("Checking out main...\n")
	if err := g.Checkout("main"); err != nil {
		return fmt.Errorf("checking out main: %w", err)
	}

	// Pull latest main
	if err := g.Pull("origin", "main"); err != nil {
		// Non-fatal if pull fails (e.g., first time)
		fmt.Printf("  %s\n", style.Dim.Render("(pull from origin/main skipped)"))
	}

	// Merge with --no-ff
	fmt.Printf("Merging %s to main...\n", branchName)
	mergeMsg := fmt.Sprintf("Merge %s: %s\n\nEpic: %s", branchName, epic.Title, epicID)
	if err := g.MergeNoFF("origin/"+branchName, mergeMsg); err != nil {
		// Abort merge on failure (best-effort cleanup)
		_ = g.AbortMerge()
		return fmt.Errorf("merge failed: %w", err)
	}
	fmt.Printf("  %s Merged successfully\n", style.Bold.Render("✓"))

	// 5. Run tests (if configured and not skipped)
	if !mqIntegrationLandSkipTests {
		testCmd := getTestCommand(r.Path)
		if testCmd != "" {
			fmt.Printf("Running tests: %s\n", testCmd)
			if err := runTestCommand(r.Path, testCmd); err != nil {
				// Tests failed - reset main
				fmt.Printf("  %s Tests failed, resetting main...\n", style.Bold.Render("✗"))
				_ = g.Checkout("main") // best-effort: need to be on main to reset
				resetErr := resetHard(g, "HEAD~1")
				if resetErr != nil {
					return fmt.Errorf("tests failed and could not reset: %w (test error: %v)", resetErr, err)
				}
				return fmt.Errorf("tests failed: %w", err)
			}
			fmt.Printf("  %s Tests passed\n", style.Bold.Render("✓"))
		} else {
			fmt.Printf("  %s\n", style.Dim.Render("(no test command configured)"))
		}
	} else {
		fmt.Printf("  %s\n", style.Dim.Render("(tests skipped)"))
	}

	// 6. Push to origin
	fmt.Printf("Pushing main to origin...\n")
	if err := g.Push("origin", "main", false); err != nil {
		// Reset on push failure
		resetErr := resetHard(g, "HEAD~1")
		if resetErr != nil {
			return fmt.Errorf("push failed and could not reset: %w (push error: %v)", resetErr, err)
		}
		return fmt.Errorf("push failed: %w", err)
	}
	fmt.Printf("  %s Pushed to origin\n", style.Bold.Render("✓"))

	// 7. Delete integration branch
	fmt.Printf("Deleting integration branch...\n")
	// Delete remote first
	if err := g.DeleteRemoteBranch("origin", branchName); err != nil {
		fmt.Printf("  %s\n", style.Dim.Render(fmt.Sprintf("(could not delete remote branch: %v)", err)))
	} else {
		fmt.Printf("  %s Deleted from origin\n", style.Bold.Render("✓"))
	}
	// Delete local
	if err := g.DeleteBranch(branchName, true); err != nil {
		fmt.Printf("  %s\n", style.Dim.Render(fmt.Sprintf("(could not delete local branch: %v)", err)))
	} else {
		fmt.Printf("  %s Deleted locally\n", style.Bold.Render("✓"))
	}

	// 8. Update epic status
	fmt.Printf("Updating epic status...\n")
	if err := bd.Close(epicID); err != nil {
		fmt.Printf("  %s\n", style.Dim.Render(fmt.Sprintf("(could not close epic: %v)", err)))
	} else {
		fmt.Printf("  %s Epic closed\n", style.Bold.Render("✓"))
	}

	// Success output
	fmt.Printf("\n%s Successfully landed integration branch\n", style.Bold.Render("✓"))
	fmt.Printf("  Epic:   %s\n", epicID)
	fmt.Printf("  Branch: %s → main\n", branchName)

	return nil
}

// findOpenMRsForIntegration finds all open merge requests targeting an integration branch.
func findOpenMRsForIntegration(bd *beads.Beads, targetBranch string) ([]*beads.Issue, error) {
	// List all open merge requests
	opts := beads.ListOptions{
		Type:   "merge-request",
		Status: "open",
	}
	allMRs, err := bd.List(opts)
	if err != nil {
		return nil, err
	}

	return filterMRsByTarget(allMRs, targetBranch), nil
}

// filterMRsByTarget filters merge requests to those targeting a specific branch.
func filterMRsByTarget(mrs []*beads.Issue, targetBranch string) []*beads.Issue {
	var result []*beads.Issue
	for _, mr := range mrs {
		fields := beads.ParseMRFields(mr)
		if fields != nil && fields.Target == targetBranch {
			result = append(result, mr)
		}
	}
	return result
}

// getTestCommand returns the test command from rig settings.
func getTestCommand(rigPath string) string {
	settingsPath := filepath.Join(rigPath, "settings", "config.json")
	settings, err := config.LoadRigSettings(settingsPath)
	if err != nil {
		return ""
	}
	if settings.MergeQueue != nil && settings.MergeQueue.TestCommand != "" {
		return settings.MergeQueue.TestCommand
	}
	return ""
}

// runTestCommand executes a test command in the given directory.
func runTestCommand(workDir, testCmd string) error {
	parts := strings.Fields(testCmd)
	if len(parts) == 0 {
		return nil
	}

	cmd := exec.Command(parts[0], parts[1:]...)
	cmd.Dir = workDir
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}

// resetHard performs a git reset --hard to the given ref.
func resetHard(g *git.Git, ref string) error {
	// We need to use the git package, but it doesn't have a Reset method
	// For now, use the internal run method via Checkout workaround
	// This is a bit of a hack but works for now
	cmd := exec.Command("git", "reset", "--hard", ref)
	cmd.Dir = g.WorkDir()
	return cmd.Run()
}

// runMqIntegrationStatus shows the status of an integration branch for an epic.
func runMqIntegrationStatus(cmd *cobra.Command, args []string) error {
	epicID := args[0]

	// Find workspace
	townRoot, err := workspace.FindFromCwdOrError()
	if err != nil {
		return fmt.Errorf("not in a Gas Town workspace: %w", err)
	}

	// Find current rig
	_, r, err := findCurrentRig(townRoot)
	if err != nil {
		return err
	}

	// Initialize beads for the rig
	bd := beads.New(r.Path)

	// Fetch epic to get stored branch name
	epic, err := bd.Show(epicID)
	if err != nil {
		if err == beads.ErrNotFound {
			return fmt.Errorf("epic '%s' not found", epicID)
		}
		return fmt.Errorf("fetching epic: %w", err)
	}

	// Get integration branch name from epic metadata (stored at create time)
	// Fall back to default template for backward compatibility with old epics
	branchName := getIntegrationBranchField(epic.Description)
	if branchName == "" {
		branchName = buildIntegrationBranchName(defaultIntegrationBranchTemplate, epicID)
	}

	// Initialize git for the rig
	g := git.NewGit(r.Path)

	// Fetch from origin to ensure we have latest refs
	if err := g.Fetch("origin"); err != nil {
		// Non-fatal, continue with local data
	}

	// Check if integration branch exists (locally or remotely)
	localExists, _ := g.BranchExists(branchName)
	remoteExists, _ := g.RemoteBranchExists("origin", branchName)

	if !localExists && !remoteExists {
		return fmt.Errorf("integration branch '%s' does not exist", branchName)
	}

	// Determine which ref to use for comparison
	ref := branchName
	if !localExists && remoteExists {
		ref = "origin/" + branchName
	}

	// Get branch creation date
	createdDate, err := g.BranchCreatedDate(ref)
	if err != nil {
		createdDate = "" // Non-fatal
	}

	// Get commits ahead of main
	aheadCount, err := g.CommitsAhead("main", ref)
	if err != nil {
		aheadCount = 0 // Non-fatal
	}

	// Query for MRs targeting this integration branch (use resolved name)
	targetBranch := branchName

	// Get all merge-request issues
	allMRs, err := bd.List(beads.ListOptions{
		Type:   "merge-request",
		Status: "", // all statuses
	})
	if err != nil {
		return fmt.Errorf("querying merge requests: %w", err)
	}

	// Filter by target branch and separate into merged/pending
	var mergedMRs, pendingMRs []*beads.Issue
	for _, mr := range allMRs {
		fields := beads.ParseMRFields(mr)
		if fields == nil || fields.Target != targetBranch {
			continue
		}

		if mr.Status == "closed" {
			mergedMRs = append(mergedMRs, mr)
		} else {
			pendingMRs = append(pendingMRs, mr)
		}
	}

	// Build output structure
	output := IntegrationStatusOutput{
		Epic:        epicID,
		Branch:      branchName,
		Created:     createdDate,
		AheadOfMain: aheadCount,
		MergedMRs:   make([]IntegrationStatusMRSummary, 0, len(mergedMRs)),
		PendingMRs:  make([]IntegrationStatusMRSummary, 0, len(pendingMRs)),
	}

	for _, mr := range mergedMRs {
		// Extract the title without "Merge: " prefix for cleaner display
		title := strings.TrimPrefix(mr.Title, "Merge: ")
		output.MergedMRs = append(output.MergedMRs, IntegrationStatusMRSummary{
			ID:    mr.ID,
			Title: title,
		})
	}

	for _, mr := range pendingMRs {
		title := strings.TrimPrefix(mr.Title, "Merge: ")
		output.PendingMRs = append(output.PendingMRs, IntegrationStatusMRSummary{
			ID:     mr.ID,
			Title:  title,
			Status: mr.Status,
		})
	}

	// JSON output
	if mqIntegrationStatusJSON {
		enc := json.NewEncoder(os.Stdout)
		enc.SetIndent("", "  ")
		return enc.Encode(output)
	}

	// Human-readable output
	return printIntegrationStatus(&output)
}

// printIntegrationStatus prints the integration status in human-readable format.
func printIntegrationStatus(output *IntegrationStatusOutput) error {
	fmt.Printf("Integration: %s\n", style.Bold.Render(output.Branch))
	if output.Created != "" {
		fmt.Printf("Created: %s\n", output.Created)
	}
	fmt.Printf("Ahead of main: %d commits\n", output.AheadOfMain)

	// Merged MRs
	fmt.Printf("\nMerged MRs (%d):\n", len(output.MergedMRs))
	if len(output.MergedMRs) == 0 {
		fmt.Printf("  %s\n", style.Dim.Render("(none)"))
	} else {
		for _, mr := range output.MergedMRs {
			fmt.Printf("  %-12s  %s\n", mr.ID, mr.Title)
		}
	}

	// Pending MRs
	fmt.Printf("\nPending MRs (%d):\n", len(output.PendingMRs))
	if len(output.PendingMRs) == 0 {
		fmt.Printf("  %s\n", style.Dim.Render("(none)"))
	} else {
		for _, mr := range output.PendingMRs {
			statusInfo := ""
			if mr.Status != "" && mr.Status != "open" {
				statusInfo = fmt.Sprintf(" (%s)", mr.Status)
			}
			fmt.Printf("  %-12s  %s%s\n", mr.ID, mr.Title, style.Dim.Render(statusInfo))
		}
	}

	return nil
}
