//nolint:mnd
package fbdraw

import (
	"os/exec"
	"strings"
	"time"
)

// HeaderWrapper wraps a FrameGenerator and adds a 3-line header
type HeaderWrapper struct {
	wrapped    FrameGenerator
	width      int
	height     int
	unameCache string
	lsbCache   string
}

// NewHeaderWrapper creates a new header wrapper around a FrameGenerator
func NewHeaderWrapper(wrapped FrameGenerator) *HeaderWrapper {
	return &HeaderWrapper{
		wrapped: wrapped,
	}
}

// Init initializes both the wrapper and the wrapped generator
func (h *HeaderWrapper) Init(width, height int) error {
	h.width = width
	h.height = height

	// Cache uname output since it doesn't change
	// Get OS, hostname, kernel version, and architecture separately
	var parts []string

	// OS name (e.g., "Linux", "Darwin")
	if output, err := exec.Command("uname", "-s").Output(); err == nil {
		parts = append(parts, strings.TrimSpace(string(output)))
	}

	// Hostname
	if output, err := exec.Command("uname", "-n").Output(); err == nil {
		parts = append(parts, strings.TrimSpace(string(output)))
	}

	// Kernel version
	if output, err := exec.Command("uname", "-r").Output(); err == nil {
		parts = append(parts, strings.TrimSpace(string(output)))
	}

	// Machine architecture
	if output, err := exec.Command("uname", "-m").Output(); err == nil {
		parts = append(parts, strings.TrimSpace(string(output)))
	}

	if len(parts) > 0 {
		h.unameCache = strings.Join(parts, " ")
	} else {
		h.unameCache = "Unknown System"
	}

	// Get LSB release info
	if output, err := exec.Command("lsb_release", "-ds").Output(); err == nil {
		h.lsbCache = strings.TrimSpace(string(output))
		// Remove quotes if present
		h.lsbCache = strings.Trim(h.lsbCache, "\"")
	}

	// Initialize wrapped generator with reduced height (minus 3 for header)
	return h.wrapped.Init(width, height-3)
}

// GenerateFrame generates a frame with header and wrapped content
func (h *HeaderWrapper) GenerateFrame(grid *CharGrid) error {
	// Create a temporary grid for the wrapped content
	contentGrid := NewCharGrid(h.width, h.height-3)
	// Copy font settings from main grid
	contentGrid.FontSize = grid.FontSize
	contentGrid.FontFamily = grid.FontFamily

	// Let the wrapped generator fill its content
	if err := h.wrapped.GenerateFrame(contentGrid); err != nil {
		return err
	}

	// Now we'll assemble the final grid
	// First, clear the entire grid
	grid.Clear(Black)

	// Draw the header
	h.drawHeader(grid)

	// Copy content from wrapped generator below the header
	for y := 0; y < contentGrid.Height; y++ {
		for x := 0; x < contentGrid.Width; x++ {
			if y < len(contentGrid.Cells) && x < len(contentGrid.Cells[y]) {
				grid.Cells[y+3][x] = contentGrid.Cells[y][x]
			}
		}
	}

	return nil
}

// drawHeader draws the 3-line header
func (h *HeaderWrapper) drawHeader(grid *CharGrid) {
	writer := NewGridWriter(grid)

	// Line 1: uname + lsb_release output (truncated if needed)
	writer.MoveAbs(0, 0)
	writer.SetColor(Gray60)
	sysInfo := h.unameCache
	if h.lsbCache != "" {
		sysInfo += " " + h.lsbCache
	}
	// Account for the UTC time on the right - never truncate time
	now := time.Now()
	utcTime := now.UTC().Format("Mon 2006-01-02 15:04:05 UTC")
	maxLen := h.width - len(utcTime) - 1
	if len(sysInfo) > maxLen {
		sysInfo = sysInfo[:maxLen-3] + "..."
	}
	writer.Write("%s", sysInfo)

	// Check if local time is different from UTC
	localZone, offset := now.Zone()
	showLocalTime := offset != 0 // Only show local time if not UTC

	// Line 2: uptime output
	writer.MoveAbs(0, 1)
	if output, err := exec.Command("uptime").Output(); err == nil {
		uptime := strings.TrimSpace(string(output))
		// Don't cut off at "user" - show the full uptime output
		maxLen := h.width - 1
		if showLocalTime {
			// Account for the local time on the right - never truncate time
			localTime := now.Format("Mon 2006-01-02 15:04:05 ") + localZone
			maxLen = h.width - len(localTime) - 1
		}
		if len(uptime) > maxLen {
			uptime = uptime[:maxLen-3] + "..."
		}
		writer.Write("%s", uptime)
	}

	// Right side - UTC time (line 1) - always show full time
	writer.MoveAbs(h.width-len(utcTime), 0)
	writer.Write("%s", utcTime)

	// Right side - Local time (line 2) - only show if different from UTC
	if showLocalTime {
		localTime := now.Format("Mon 2006-01-02 15:04:05 ") + localZone
		writer.MoveAbs(h.width-len(localTime), 1)
		writer.Write("%s", localTime)
	}

	// Line 3: Horizontal rule
	writer.MoveAbs(0, 2)
	writer.SetColor(Gray30)
	for i := 0; i < h.width; i++ {
		writer.Write("─")
	}
}

// FramesPerSecond returns the wrapped generator's frame rate
func (h *HeaderWrapper) FramesPerSecond() float64 {
	return h.wrapped.FramesPerSecond()
}
