package cli

import (
	"fmt"
	"io"
	"log"
	"os"
	"strings"
	"sync"
)

func logTaskStatus(taskLabel, message string) {
	log.Printf("%s: %s", taskLabel, message)
}

// ProgressReporter records a status message for a task label.
type ProgressReporter func(string, string)

// NewProgressReporter returns a function that tracks per-task status messages.
//
// Each update is logged as a single line. When output is a terminal, tasks are
// additionally printed in a table format, which is updated on each call.
func NewProgressReporter(taskLabels []string, output io.Writer) ProgressReporter {
	if len(taskLabels) < 2 {
		return logTaskStatus
	}

	file, ok := output.(*os.File)
	if !ok || !IsTerminalFile(file) {
		return logTaskStatus
	}

	var (
		mu          sync.Mutex
		prevRows    int
		tasks       = make(map[string]string, len(taskLabels))
		maxLabelLen = maxStringLen(taskLabels)
	)

	return func(taskLabel, message string) {
		mu.Lock()
		defer mu.Unlock()
		tasks[taskLabel] = message
		if prevRows > 0 { // Clear previous lines
			fmt.Fprint(output, strings.Repeat("\033[F\033[K", prevRows))
		}
		logTaskStatus(taskLabel, message)
		prevRows = 0
		width := TerminalWidth(file)
		if width <= 0 {
			return
		}
		fmt.Fprintln(output) // Add a blank line before the table.
		prevRows++
		for _, label := range taskLabels {
			lineLen, _ := fmt.Fprintf(
				output, "%-*s: %s\n", maxLabelLen, label, tasks[label],
			)
			contentLen := lineLen - 1 // fmt.Fprintf counted the trailing newline.
			prevRows += (contentLen-1)/width + 1
		}
	}
}

// maxStringLen returns the length of the longest string in strs.
func maxStringLen(strs []string) (max int) {
	for _, s := range strs {
		if len(s) > max {
			max = len(s)
		}
	}
	return
}
