package monitoring

import (
	"context"
	"fmt"
	"strings"
	"time"
)

// UIMetric represents a metric for UI display
type UIMetric struct {
	Name      string
	Value     string
	Status    string // "ok", "warning", "error"
	Timestamp time.Time
	Error     string
}

// UIMetricGroup represents a group of metrics for UI display
type UIMetricGroup struct {
	Title   string
	Metrics []UIMetric
	Errors  []string
}

// UIExporter exports metrics in a format suitable for UI display
type UIExporter struct {
	Collectors []Collector
}

func NewUIExporter(collectors ...Collector) *UIExporter {
	return &UIExporter{Collectors: collectors}
}

// Export collects all metrics and formats them for UI
func (e *UIExporter) Export(ctx context.Context) []UIMetricGroup {
	groups := []UIMetricGroup{}

	for _, collector := range e.Collectors {
		collection := collector.Collect(ctx)
		// Capitalize first letter
		name := collector.Name()
		if len(name) > 0 {
			name = strings.ToUpper(name[:1]) + name[1:]
		}
		group := UIMetricGroup{
			Title:   name,
			Metrics: []UIMetric{},
			Errors:  collection.Errors,
		}

		for _, metric := range collection.Metrics {
			status := "ok"
			value := formatMetricValue(metric)

			// Determine status based on metric type and value
			if metric.Name == "zfs_pool_health" {
				if metric.Value == 0.0 {
					status = "error"
				} else if metric.Value == 0.5 {
					status = "warning"
				}
			} else if metric.Name == "smart_health" {
				if metric.Value == 0.0 {
					status = "error"
				}
			} else if metric.Name == "service_state" {
				if metric.Value == 0.0 {
					status = "error"
				}
			} else if strings.HasPrefix(metric.Name, "host_load") {
				if metric.Value > 10.0 {
					status = "warning"
				}
				if metric.Value > 20.0 {
					status = "error"
				}
			}

			group.Metrics = append(group.Metrics, UIMetric{
				Name:      formatMetricName(metric),
				Value:     value,
				Status:    status,
				Timestamp: time.Now(),
			})
		}

		groups = append(groups, group)
	}

	return groups
}

func formatMetricName(metric MetricValue) string {
	name := metric.Name
	if len(metric.Labels) > 0 {
		labels := []string{}
		for k, v := range metric.Labels {
			labels = append(labels, fmt.Sprintf("%s=%s", k, v))
		}
		name = fmt.Sprintf("%s{%s}", name, strings.Join(labels, ", "))
	}
	return name
}

func formatMetricValue(metric MetricValue) string {
	switch metric.Name {
	case "zfs_pool_health":
		if metric.Value == 1.0 {
			return "ONLINE"
		} else if metric.Value == 0.5 {
			return "DEGRADED"
		}
		return "FAULTED"
	case "zfs_pool_scrub_in_progress":
		if metric.Value == 1.0 {
			return "In Progress"
		}
		return "Idle"
	case "smart_health":
		if metric.Value == 1.0 {
			return "PASSED"
		}
		return "FAILED"
	case "service_state":
		if metric.Value == 1.0 {
			return "Running"
		}
		return "Stopped"
	case "host_load1", "host_load5", "host_load15":
		return fmt.Sprintf("%.2f", metric.Value)
	case "host_memory_total_bytes", "host_memory_free_bytes", "host_memory_available_bytes":
		return formatBytes(metric.Value)
	default:
		return fmt.Sprintf("%.2f", metric.Value)
	}
}

func formatBytes(bytes float64) string {
	units := []string{"B", "KB", "MB", "GB", "TB"}
	value := bytes
	unit := 0
	for value >= 1024 && unit < len(units)-1 {
		value /= 1024
		unit++
	}
	return fmt.Sprintf("%.2f %s", value, units[unit])
}

