package main

import (
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/steveyegge/beads/internal/debug"
	"github.com/steveyegge/beads/internal/git"
)

// ensureForkProtection prevents contributors from accidentally committing
// the upstream issue database when working in a fork.
//
// When we detect this is a fork (origin != steveyegge/beads), we add
// .beads/issues.jsonl to .git/info/exclude so it won't be staged.
// This is a per-clone setting that doesn't modify tracked files.
func ensureForkProtection() {
	// Find git root
	gitRoot := git.GetRepoRoot()
	if gitRoot == "" {
		return // Not in a git repo
	}

	// Check if this is the upstream repo (maintainers)
	if isUpstreamRepo(gitRoot) {
		return // Maintainers can commit issues.jsonl
	}

	// Check if already excluded
	excludePath := filepath.Join(gitRoot, ".git", "info", "exclude")
	if isAlreadyExcluded(excludePath) {
		return
	}

	// Add to .git/info/exclude
	if err := addToExclude(excludePath); err != nil {
		debug.Printf("fork protection: failed to update exclude: %v", err)
		return
	}

	debug.Printf("Fork detected: .beads/issues.jsonl excluded from git staging")
}

// isUpstreamRepo checks if origin remote points to the upstream beads repo
func isUpstreamRepo(gitRoot string) bool {
	cmd := exec.Command("git", "-C", gitRoot, "remote", "get-url", "origin")
	out, err := cmd.Output()
	if err != nil {
		return false // Can't determine, assume fork for safety
	}

	remote := strings.TrimSpace(string(out))

	// Check for upstream repo patterns
	upstreamPatterns := []string{
		"steveyegge/beads",
		"git@github.com:steveyegge/beads",
		"https://github.com/steveyegge/beads",
	}

	for _, pattern := range upstreamPatterns {
		if strings.Contains(remote, pattern) {
			return true
		}
	}

	return false
}

// isAlreadyExcluded checks if issues.jsonl is already in the exclude file
func isAlreadyExcluded(excludePath string) bool {
	content, err := os.ReadFile(excludePath) //nolint:gosec // G304: path is constructed from git root, not user input
	if err != nil {
		return false // File doesn't exist or can't read, not excluded
	}

	return strings.Contains(string(content), ".beads/issues.jsonl")
}

// addToExclude adds the issues.jsonl pattern to .git/info/exclude
func addToExclude(excludePath string) error {
	// Ensure the directory exists
	dir := filepath.Dir(excludePath)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}

	// Open for append (create if doesn't exist)
	f, err := os.OpenFile(excludePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) //nolint:gosec // G302: .git/info/exclude should be world-readable
	if err != nil {
		return err
	}
	defer f.Close()

	// Add our exclusion with a comment
	_, err = f.WriteString("\n# Beads: prevent fork from committing upstream issue database\n.beads/issues.jsonl\n")
	return err
}
