package shell

import (
	"fmt"
	"strings"
	"time"

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

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

// Logger escribe logs de la ejecución paralela a disco.
type Logger struct {
	logsDir   string
	sessionID string
}

// NewLogger crea un logger para la sesión actual.
func NewLogger(repoRoot string) core.Result[*Logger] {
	sessionID := time.Now().Format("20060102-150405")
	logsDir := repoRoot + "/logs"

	result := dfshell.MkdirAll(logsDir)
	if result.IsErr() {
		return core.Err[*Logger](result.Error())
	}

	return core.Ok(&Logger{
		logsDir:   logsDir,
		sessionID: sessionID,
	})
}

// LogIssueStart registra el inicio de ejecución de una issue.
func (l *Logger) LogIssueStart(issue pcore.Issue) {
	msg := fmt.Sprintf("[%s] START Issue #%04d - %s\n",
		time.Now().Format("15:04:05"), issue.Number, issue.Title)
	l.appendToSession(msg)
}

// LogIssueResult registra el resultado de una issue.
func (l *Logger) LogIssueResult(result pcore.ExecutionResult) {
	status := "SUCCESS"
	if !result.Success {
		status = "FAILED"
	}

	msg := fmt.Sprintf("[%s] %s Issue #%04d - %s (duration: %s)",
		time.Now().Format("15:04:05"), status,
		result.Issue.Number, result.Issue.Title, result.Duration)

	if result.Error != "" {
		msg += "\n  Error: " + result.Error
	}
	msg += "\n"

	l.appendToSession(msg)

	// Log individual por issue
	issueLogFile := fmt.Sprintf("%s/issue-%04d-%s.log",
		l.logsDir, result.Issue.Number, l.sessionID)
	content := fmt.Sprintf("Issue #%04d - %s\nStatus: %s\nDuration: %s\n",
		result.Issue.Number, result.Issue.Title, status, result.Duration)
	if result.Error != "" {
		content += "Error:\n" + result.Error + "\n"
	}
	dfshell.WriteString(issueLogFile, content)
}

// WriteSummary escribe el resumen consolidado.
func (l *Logger) WriteSummary(results []pcore.ExecutionResult) core.Result[string] {
	summaryFile := fmt.Sprintf("%s/summary-%s.txt", l.logsDir, l.sessionID)

	var b strings.Builder
	b.WriteString("=" + strings.Repeat("=", 59) + "\n")
	b.WriteString(fmt.Sprintf(" Parallel Execution Summary — %s\n", l.sessionID))
	b.WriteString("=" + strings.Repeat("=", 59) + "\n\n")

	succeeded := 0
	failed := 0
	for _, r := range results {
		if r.Success {
			succeeded++
		} else {
			failed++
		}
	}

	b.WriteString(fmt.Sprintf("Total:     %d\n", len(results)))
	b.WriteString(fmt.Sprintf("Succeeded: %d\n", succeeded))
	b.WriteString(fmt.Sprintf("Failed:    %d\n\n", failed))

	b.WriteString("Results:\n")
	b.WriteString(strings.Repeat("-", 60) + "\n")

	for _, r := range results {
		status := "✓"
		if !r.Success {
			status = "✗"
		}
		b.WriteString(fmt.Sprintf("  %s #%04d %-30s %s\n",
			status, r.Issue.Number, r.Issue.Title, r.Duration))
		if r.Error != "" {
			b.WriteString(fmt.Sprintf("    Error: %s\n", truncate(r.Error, 80)))
		}
	}

	b.WriteString(strings.Repeat("-", 60) + "\n")

	writeResult := dfshell.WriteString(summaryFile, b.String())
	if writeResult.IsErr() {
		return core.Err[string](writeResult.Error())
	}

	return core.Ok(summaryFile)
}

// SessionLogFile retorna la ruta del log de sesión.
func (l *Logger) SessionLogFile() string {
	return fmt.Sprintf("%s/parallel-execution-%s.log", l.logsDir, l.sessionID)
}

func (l *Logger) appendToSession(msg string) {
	logFile := l.SessionLogFile()
	dfshell.AppendFile(logFile, []byte(msg))
}

func truncate(s string, max int) string {
	if len(s) <= max {
		return s
	}
	return s[:max-3] + "..."
}
