package tui

import (
	"fmt"
	"strings"

	"github.com/schmitthub/clawker/internal/iostreams"
	cltext "github.com/schmitthub/clawker/internal/text"
)

// HeaderConfig configures a header component.
type HeaderConfig struct {
	Title     string
	Subtitle  string
	Timestamp string
	Width     int
}

// RenderHeader renders a header with title, optional subtitle, and timestamp.
func RenderHeader(cfg HeaderConfig) string {
	title := iostreams.HeaderTitleStyle.Render(cfg.Title)

	var parts []string
	parts = append(parts, title)

	if cfg.Subtitle != "" {
		parts = append(parts, iostreams.HeaderSubtitleStyle.Render(cfg.Subtitle))
	}

	left := strings.Join(parts, " ")

	if cfg.Timestamp != "" {
		return iostreams.FlexRow(cfg.Width, left, "", iostreams.MutedStyle.Render(cfg.Timestamp))
	}

	return left
}

// DashHeaderConfig configures a full-width dashboard header bar.
type DashHeaderConfig struct {
	Title    string // e.g., "Firewall Bypass"
	Subtitle string // e.g., agent name — rendered muted on the right
	Width    int
}

// RenderDashHeader renders a full-width dashboard header bar:
//
//	━━ Title ━━━━━━━━━━━━━━━━━━━━ subtitle ━━
//
// Title is bold+primary, fill and subtitle are muted.
func RenderDashHeader(cs *iostreams.ColorScheme, cfg DashHeaderConfig) string {
	title := fmt.Sprintf("  ━━ %s ", cfg.Title)
	subtitle := fmt.Sprintf(" %s ━━", cfg.Subtitle)

	titleRendered := cs.Bold(cs.Primary(title))
	subtitleRendered := iostreams.MutedStyle.Render(subtitle)

	titleWidth := cltext.CountVisibleWidth(titleRendered)
	subtitleWidth := cltext.CountVisibleWidth(subtitleRendered)
	fillWidth := cfg.Width - titleWidth - subtitleWidth
	if fillWidth < 3 {
		fillWidth = 3
	}
	fill := iostreams.MutedStyle.Render(strings.Repeat("━", fillWidth))

	return titleRendered + fill + subtitleRendered
}

// StatusConfig configures a status indicator.
type StatusConfig struct {
	Status string
	Label  string
}

// RenderStatus renders a status indicator like "● RUNNING".
// Delegates to iostreams.StatusIndicator for style and symbol selection.
func RenderStatus(cfg StatusConfig) string {
	style, symbol := iostreams.StatusIndicator(cfg.Status)
	if cfg.Label == "" {
		cfg.Label = strings.ToUpper(cfg.Status)
	}
	return style.Render(symbol + " " + cfg.Label)
}

// RenderBadge renders text as a styled badge.
// If no render function is provided, uses BadgeStyle.
func RenderBadge(text string, render ...func(string) string) string {
	if len(render) > 0 {
		return render[0](text)
	}
	return iostreams.BadgeStyle.Render(text)
}

// RenderCountBadge renders a count with a label, like "3 tasks".
func RenderCountBadge(count int, label string) string {
	countStr := iostreams.CountStyle.Render(fmt.Sprintf("%d", count))
	return countStr + " " + iostreams.MutedStyle.Render(label)
}

// ProgressConfig configures a progress indicator.
type ProgressConfig struct {
	Current int
	Total   int
	Width   int
	ShowBar bool
}

// RenderProgress renders a progress indicator.
// If ShowBar is true, renders a progress bar.
// Otherwise renders "current/total".
func RenderProgress(cfg ProgressConfig) string {
	if cfg.Total <= 0 {
		return iostreams.MutedStyle.Render("-")
	}

	if !cfg.ShowBar {
		return fmt.Sprintf("%d/%d", cfg.Current, cfg.Total)
	}

	// Render progress bar
	width := cfg.Width
	if width < 3 {
		width = 10
	}

	barWidth := width - 2 // Account for brackets
	filled := 0
	if cfg.Total > 0 {
		filled = (cfg.Current * barWidth) / cfg.Total
	}
	filled = max(0, min(filled, barWidth))
	empty := barWidth - filled

	bar := "[" +
		iostreams.SuccessStyle.Render(strings.Repeat("=", filled)) +
		iostreams.MutedStyle.Render(strings.Repeat("-", empty)) +
		"]"

	return bar
}

// RenderDivider renders a horizontal divider line.
func RenderDivider(width int) string {
	if width <= 0 {
		return ""
	}
	return iostreams.DividerStyle.Render(strings.Repeat("\u2500", width)) // ─
}

// RenderLabeledDivider renders a divider with a centered label.
func RenderLabeledDivider(label string, width int) string {
	if width <= 0 {
		return ""
	}

	labelLen := cltext.CountVisibleWidth(label)
	if labelLen+4 >= width {
		return RenderDivider(width)
	}

	leftWidth := (width - labelLen - 2) / 2
	rightWidth := width - labelLen - 2 - leftWidth

	left := strings.Repeat("\u2500", leftWidth) // ─
	right := strings.Repeat("\u2500", rightWidth)

	return iostreams.DividerStyle.Render(left) + " " + iostreams.MutedStyle.Render(label) + " " + iostreams.DividerStyle.Render(right)
}

// RenderLeftLabeledDivider renders a divider with a left-aligned label followed by a trailing rule.
func RenderLeftLabeledDivider(label string, width int) string {
	if width <= 0 {
		return ""
	}

	labelLen := cltext.CountVisibleWidth(label)
	if labelLen+1 >= width {
		return RenderDivider(width)
	}

	trailWidth := width - labelLen - 1
	trail := strings.Repeat("\u2500", trailWidth) // ─

	return iostreams.MutedStyle.Render(label) + " " + iostreams.DividerStyle.Render(trail)
}

// RenderEmptyState renders a centered empty state message.
func RenderEmptyState(message string, width, height int) string {
	return iostreams.CenterInRect(iostreams.EmptyStateStyle.Render(message), width, height)
}

// RenderError renders an error message.
func RenderError(err error, width int) string {
	if err == nil {
		return ""
	}

	errorText := iostreams.ErrorStyle.Render("\u2717 Error: ") + err.Error()
	if width > 0 {
		wrapped := cltext.WordWrap(errorText, width)
		return wrapped
	}
	return errorText
}

// RenderLabelValue renders a label-value pair.
func RenderLabelValue(label, value string) string {
	return iostreams.LabelStyle.Render(label+":") + " " + iostreams.ValueStyle.Render(value)
}

// KeyValuePair represents a key-value pair for display.
type KeyValuePair struct {
	Key   string
	Value string
}

// RenderKeyValueTable renders a table of key-value pairs.
func RenderKeyValueTable(pairs []KeyValuePair, width int) string {
	if len(pairs) == 0 {
		return ""
	}

	// Find max key width
	maxKeyLen := 0
	for _, p := range pairs {
		keyLen := cltext.CountVisibleWidth(p.Key)
		if keyLen > maxKeyLen {
			maxKeyLen = keyLen
		}
	}

	// Render pairs with aligned colons
	var lines []string
	for _, p := range pairs {
		key := iostreams.LabelStyle.Width(maxKeyLen + 1).Render(p.Key + ":")
		val := iostreams.ValueStyle.Render(p.Value)
		lines = append(lines, key+" "+val)
	}

	return strings.Join(lines, "\n")
}

// RenderTable renders a simple table with headers and rows.
type TableConfig struct {
	Headers   []string
	Rows      [][]string
	ColWidths []int
	Width     int
}

// RenderTable renders a simple table.
func RenderTable(cfg TableConfig) string {
	if len(cfg.Headers) == 0 {
		return ""
	}

	// Calculate column widths if not specified
	colWidths := cfg.ColWidths
	if len(colWidths) == 0 {
		colWidths = make([]int, len(cfg.Headers))
		available := cfg.Width - (len(cfg.Headers) - 1) // Gap between columns
		colWidth := available / len(cfg.Headers)
		for i := range colWidths {
			colWidths[i] = colWidth
		}
	}

	var lines []string

	// Render header
	var headerParts []string
	for i, h := range cfg.Headers {
		width := colWidths[i]
		headerParts = append(headerParts, iostreams.HeaderStyle.Width(width).Render(cltext.Truncate(h, width)))
	}
	lines = append(lines, strings.Join(headerParts, " "))

	// Render divider
	var dividerParts []string
	for _, w := range colWidths {
		dividerParts = append(dividerParts, strings.Repeat("\u2500", w))
	}
	lines = append(lines, iostreams.DividerStyle.Render(strings.Join(dividerParts, " ")))

	// Render rows
	for _, row := range cfg.Rows {
		var rowParts []string
		for i := range cfg.Headers {
			width := colWidths[i]
			val := ""
			if i < len(row) {
				val = row[i]
			}
			rowParts = append(rowParts, cltext.PadRight(cltext.Truncate(val, width), width))
		}
		lines = append(lines, strings.Join(rowParts, " "))
	}

	return strings.Join(lines, "\n")
}

// RenderPercentage renders a percentage value with appropriate styling.
func RenderPercentage(value float64) string {
	style := iostreams.MutedStyle
	if value >= 80 {
		style = iostreams.ErrorStyle
	} else if value >= 60 {
		style = iostreams.WarningStyle
	}
	return style.Render(fmt.Sprintf("%.1f%%", value))
}

// RenderBytes renders a byte count in human-readable format.
func RenderBytes(bytes int64) string {
	const (
		KB = 1024
		MB = KB * 1024
		GB = MB * 1024
	)

	switch {
	case bytes >= GB:
		return fmt.Sprintf("%.1f GB", float64(bytes)/GB)
	case bytes >= MB:
		return fmt.Sprintf("%.1f MB", float64(bytes)/MB)
	case bytes >= KB:
		return fmt.Sprintf("%.1f KB", float64(bytes)/KB)
	default:
		return fmt.Sprintf("%d B", bytes)
	}
}

// RenderTag renders a tag-like element.
// If no render function is provided, uses TagStyle.
func RenderTag(text string, render ...func(string) string) string {
	if len(render) > 0 {
		return render[0](text)
	}
	return iostreams.TagStyle.Render(text)
}

// RenderTags renders multiple tags inline.
// If no render function is provided, uses TagStyle.
func RenderTags(tags []string, render ...func(string) string) string {
	if len(tags) == 0 {
		return ""
	}

	var rendered []string
	for _, tag := range tags {
		rendered = append(rendered, RenderTag(tag, render...))
	}

	return strings.Join(rendered, " ")
}
