package printer

import (
	"fmt"
	"io"
	"strings"
)

// justify justifies value into width.
//
// align=">" right-justifies; anything else left-justifies.
func justify(value any, width int, align string) string {
	s := fmt.Sprintf("%v", value)
	if align == ">" {
		return fmt.Sprintf("%*s", width, s)
	}
	return fmt.Sprintf("%-*s", width, s)
}

// FormatBytes formats a byte count in 1024-base binary units (B, K, M, G,
// T, P).
//
// Used for operator-facing display. Note vmctl prints SI (1000-base) units
// inline; this formatter is for our own output, so the same byte count may
// display slightly differently here vs. vmctl. Matches cli_table.format_bytes.
func FormatBytes(n float64) string {
	if n < 1024 {
		return fmt.Sprintf("%dB", int64(n))
	}
	f := float64(n)
	for _, unit := range []string{"K", "M", "G", "T", "P"} {
		f /= 1024
		if f < 1024 {
			return fmt.Sprintf("%.2f%s", f, unit)
		}
	}
	return fmt.Sprintf("%.2fP", f)
}

// ColumnSpec is shared table-column metadata for fixed-width text tables
// (serve job output, loop renderers).
//
// Align is ">" for right-justify, anything else for left-justify.
type ColumnSpec struct {
	Name  string
	Align string
}

// PrintRow writes header row `cols` justified into `widths`, joined by two
// spaces.
func PrintRow(w io.Writer, cols []ColumnSpec, widths []int) {
	parts := make([]string, len(cols))
	for i, c := range cols {
		parts[i] = justify(c.Name, widths[i], c.Align)
	}
	fmt.Fprintln(w, strings.Join(parts, "  "))
}

// PrintValues writes one data row.
//
// Each value is formatted per the corresponding ColumnSpec, joined by two
// spaces.
func PrintValues(w io.Writer, values []any, cols []ColumnSpec, widths []int) {
	parts := make([]string, len(values))
	for i, v := range values {
		parts[i] = justify(v, widths[i], cols[i].Align)
	}
	fmt.Fprintln(w, strings.Join(parts, "  "))
}

// PrintSeparator writes a row of "-" runs matching widths, joined by two
// spaces.
//
// Used as the header/body divider.
func PrintSeparator(w io.Writer, widths []int) {
	parts := make([]string, len(widths))
	for i, wd := range widths {
		parts[i] = strings.Repeat("-", wd)
	}
	fmt.Fprintln(w, strings.Join(parts, "  "))
}

// Printf writes format plus a trailing newline to w.
//
// Write errors are ignored: the sink is a terminal, pipe, or log stream
// where nothing useful can be done on failure.
func Printf(w io.Writer, format string, args ...any) {
	_, _ = fmt.Fprintf(w, format+"\n", args...)
}
