package shell

import (
	"fmt"
	"strings"
	"time"

	"github.com/lucasdataproyects/devfactory/core"
	dfshell "github.com/lucasdataproyects/devfactory/shell"

	pcore "github.com/lucasdataproyects/parallel-executor/core"
)

const defaultTimeout = 30 * time.Minute

// ExecuteIssue ejecuta claude para resolver una issue en un worktree.
// Invoca `claude -p` con el prompt de fix-issue dentro del worktree.
func ExecuteIssue(spec pcore.WorktreeSpec, timeout time.Duration) pcore.ExecutionResult {
	start := time.Now()

	if timeout == 0 {
		timeout = defaultTimeout
	}

	prompt := fmt.Sprintf(
		"Read the issue file dev/issues/%04d-*.md and implement all tasks. "+
			"Run tests after each change. Follow pure core / impure shell pattern. "+
			"When done, commit all changes with a descriptive message.",
		spec.Issue.Number,
	)

	result := dfshell.RunWithTimeout("claude",
		timeout,
		"-p", prompt,
		"--cwd", spec.WorkDir,
	)

	duration := time.Since(start).Round(time.Second).String()

	if result.IsErr() {
		return pcore.ExecutionResult{
			Issue:    spec.Issue,
			Success:  false,
			Duration: duration,
			Error:    result.Error().Error(),
		}
	}

	cmdResult := result.Unwrap()
	if !cmdResult.Success() {
		return pcore.ExecutionResult{
			Issue:    spec.Issue,
			Success:  false,
			Duration: duration,
			Error:    cmdResult.Stderr,
		}
	}

	return pcore.ExecutionResult{
		Issue:    spec.Issue,
		Success:  true,
		Duration: duration,
	}
}

// PushWorktreeBranch hace push de la branch del worktree al remote.
func PushWorktreeBranch(spec pcore.WorktreeSpec) core.Result[struct{}] {
	result := dfshell.Run("git", "-C", spec.WorkDir,
		"push", "-u", "origin", spec.BranchName,
	)
	if result.IsErr() {
		return core.Err[struct{}](fmt.Errorf("push failed for %s: %w",
			spec.BranchName, result.Error()))
	}
	return core.Ok(struct{}{})
}

// MergeBranchToMaster mergea una branch a master con --no-ff.
func MergeBranchToMaster(branchName string, repoRoot string) core.Result[struct{}] {
	// Checkout master
	result := dfshell.Run("git", "-C", repoRoot, "checkout", "master")
	if result.IsErr() {
		return core.Err[struct{}](result.Error())
	}

	// Merge --no-ff
	message := fmt.Sprintf("merge: %s — parallel execution", branchName)
	result = dfshell.Run("git", "-C", repoRoot,
		"merge", "--no-ff", "-m", message, branchName,
	)
	if result.IsErr() {
		return core.Err[struct{}](fmt.Errorf("merge failed for %s: %w",
			branchName, result.Error()))
	}

	return core.Ok(struct{}{})
}

// DeleteBranch elimina una branch local.
func DeleteBranch(branchName string, repoRoot string) core.Result[struct{}] {
	result := dfshell.Run("git", "-C", repoRoot, "branch", "-d", branchName)
	if result.IsErr() {
		return core.Err[struct{}](result.Error())
	}
	return core.Ok(struct{}{})
}

// ReadIssueFiles lee todos los archivos de issues de un directorio.
func ReadIssueFiles(issuesDir string) core.Result[map[string]string] {
	entries := dfshell.ListDir(issuesDir)
	if entries.IsErr() {
		return core.Err[map[string]string](entries.Error())
	}

	files := make(map[string]string)
	for _, entry := range entries.Unwrap() {
		if !strings.HasSuffix(entry, ".md") || entry == "README.md" {
			continue
		}
		content := dfshell.ReadString(issuesDir + "/" + entry)
		if content.IsOk() {
			files[entry] = content.Unwrap()
		}
	}

	return core.Ok(files)
}
