package orchestrator

import (
	"fmt"
	"time"

	"github.com/Fimeg/RedFlag/aggregator-agent/internal/client"
	"github.com/Fimeg/RedFlag/aggregator-agent/internal/system"
)

// SystemScanner scans system metrics (CPU, memory, processes, uptime)
type SystemScanner struct {
	agentVersion string
}

// NewSystemScanner creates a new system scanner
func NewSystemScanner(agentVersion string) *SystemScanner {
	return &SystemScanner{
		agentVersion: agentVersion,
	}
}

// IsAvailable always returns true since system scanning is always available
func (s *SystemScanner) IsAvailable() bool {
	return true
}

// ScanSystem collects system information and returns proper system metrics
func (s *SystemScanner) ScanSystem() ([]SystemMetric, error) {
	sysInfo, err := system.GetSystemInfo(s.agentVersion)
	if err != nil {
		return nil, fmt.Errorf("failed to get system info: %w", err)
	}

	// Convert system info to proper SystemMetric format
	var metrics []SystemMetric

	// CPU info metric
	cpuMetric := SystemMetric{
		MetricName:     "system-cpu",
		MetricType:     "cpu",
		CurrentValue:   fmt.Sprintf("%d cores, %d threads", sysInfo.CPUInfo.Cores, sysInfo.CPUInfo.Threads),
		AvailableValue: sysInfo.CPUInfo.ModelName,
		Severity:       "low",
		Metadata: map[string]interface{}{
			"cpu_model":   sysInfo.CPUInfo.ModelName,
			"cpu_cores":   fmt.Sprintf("%d", sysInfo.CPUInfo.Cores),
			"cpu_threads": fmt.Sprintf("%d", sysInfo.CPUInfo.Threads),
		},
	}
	metrics = append(metrics, cpuMetric)

	// Memory info metric
	memMetric := SystemMetric{
		MetricName:     "system-memory",
		MetricType:     "memory",
		CurrentValue:   fmt.Sprintf("%.1f%% used", sysInfo.MemoryInfo.UsedPercent),
		AvailableValue: fmt.Sprintf("%d GB total", sysInfo.MemoryInfo.Total/(1024*1024*1024)),
		Severity:       determineMemorySeverity(sysInfo.MemoryInfo.UsedPercent),
		Metadata: map[string]interface{}{
			"memory_total":        fmt.Sprintf("%d", sysInfo.MemoryInfo.Total),
			"memory_used":         fmt.Sprintf("%d", sysInfo.MemoryInfo.Used),
			"memory_available":    fmt.Sprintf("%d", sysInfo.MemoryInfo.Available),
			"memory_used_percent": fmt.Sprintf("%.1f", sysInfo.MemoryInfo.UsedPercent),
		},
	}
	metrics = append(metrics, memMetric)

	// Process count metric
	processMetric := SystemMetric{
		MetricName:     "system-processes",
		MetricType:     "processes",
		CurrentValue:   fmt.Sprintf("%d processes", sysInfo.RunningProcesses),
		AvailableValue: "n/a",
		Severity:       "low",
		Metadata: map[string]interface{}{
			"process_count": fmt.Sprintf("%d", sysInfo.RunningProcesses),
		},
	}
	metrics = append(metrics, processMetric)

	// Uptime metric
	uptimeMetric := SystemMetric{
		MetricName:     "system-uptime",
		MetricType:     "uptime",
		CurrentValue:   sysInfo.Uptime,
		AvailableValue: "n/a",
		Severity:       "low",
		Metadata: map[string]interface{}{
			"uptime": sysInfo.Uptime,
		},
	}
	metrics = append(metrics, uptimeMetric)

	// Reboot required metric (if applicable)
	if sysInfo.RebootRequired {
		rebootMetric := SystemMetric{
			MetricName:     "system-reboot",
			MetricType:     "reboot",
			CurrentValue:   "required",
			AvailableValue: "n/a",
			Severity:       "important",
			Metadata: map[string]interface{}{
				"reboot_required": "true",
				"reboot_reason":   sysInfo.RebootReason,
			},
		}
		metrics = append(metrics, rebootMetric)
	}

	return metrics, nil
}

// Name returns the scanner name
func (s *SystemScanner) Name() string {
	return "System Metrics Reporter"
}

// --- Legacy Compatibility Methods ---

// Scan collects system information and returns it as "updates" for reporting (LEGACY)
// This method is kept for backwards compatibility with the old Scanner interface
func (s *SystemScanner) Scan() ([]client.UpdateReportItem, error) {
	metrics, err := s.ScanSystem()
	if err != nil {
		return nil, err
	}

	// Convert proper SystemMetric back to legacy UpdateReportItem format
	var items []client.UpdateReportItem

	for _, metric := range metrics {
		item := client.UpdateReportItem{
			PackageName:        metric.MetricName,
			CurrentVersion:     metric.CurrentValue,
			AvailableVersion:   metric.AvailableValue,
			PackageType:        "system",
			Severity:           metric.Severity,
			PackageDescription: fmt.Sprintf("System %s: %s", metric.MetricType, metric.MetricName),
			Metadata:           metric.Metadata,
		}
		items = append(items, item)
	}

	return items, nil
}

// --- Typed Scanner Implementation ---

// GetType returns the scanner type
func (s *SystemScanner) GetType() ScannerType {
	return ScannerTypeSystem
}

// ScanTyped returns typed results (new implementation)
func (s *SystemScanner) ScanTyped() (TypedScannerResult, error) {
	startTime := time.Now()

	metrics, err := s.ScanSystem()
	if err != nil {
		return TypedScannerResult{
			ScannerName: s.Name(),
			ScannerType: ScannerTypeSystem,
			Error:       err,
			Status:      "failed",
			Duration:    time.Since(startTime).Milliseconds(),
		}, err
	}

	return TypedScannerResult{
		ScannerName: s.Name(),
		ScannerType: ScannerTypeSystem,
		SystemData:  metrics,
		Status:      "success",
		Duration:    time.Since(startTime).Milliseconds(),
	}, nil
}

// determineMemorySeverity returns severity based on memory usage percentage
func determineMemorySeverity(usedPercent float64) string {
	switch {
	case usedPercent >= 95:
		return "critical"
	case usedPercent >= 90:
		return "important"
	case usedPercent >= 80:
		return "moderate"
	default:
		return "low"
	}
}
