package orchestrator

import (
	"fmt"
	"log"
	"time"

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

// === Type Conversion Functions ===
// These functions convert scanner-specific metrics to the generic UpdateReportItem format
// This maintains compatibility with the existing Scanner interface while preserving data

// convertStorageToUpdates converts StorageMetric slices to UpdateReportItem format
func convertStorageToUpdates(metrics []StorageMetric) []client.UpdateReportItem {
	log.Printf("[HISTORY] [agent] [storage] converting %d storage metrics to update items timestamp=%s",
		len(metrics), time.Now().Format(time.RFC3339))

	updates := make([]client.UpdateReportItem, 0, len(metrics))
	for _, metric := range metrics {
		update := client.UpdateReportItem{
			// Map storage metrics to package-like structure for compatibility
			PackageType:        "storage",
			PackageName:        metric.Mountpoint,
			PackageDescription: fmt.Sprintf("Storage metrics for %s (%s)", metric.Mountpoint, metric.Filesystem),
			CurrentVersion:     fmt.Sprintf("%.1f%% used", metric.UsedPercent),
			AvailableVersion:   fmt.Sprintf("%.1f GB free", float64(metric.AvailableBytes)/1024/1024/1024),
			Severity:           metric.Severity,
			RepositorySource:   metric.Device,
			SizeBytes:          metric.TotalBytes,
			Metadata: map[string]interface{}{
				"mountpoint":     metric.Mountpoint,
				"filesystem":     metric.Filesystem,
				"device":         metric.Device,
				"disk_type":      metric.DiskType,
				"total_bytes":    metric.TotalBytes,
				"used_bytes":     metric.UsedBytes,
				"available_bytes": metric.AvailableBytes,
				"used_percent":   metric.UsedPercent,
				"is_root":        metric.IsRoot,
				"is_largest":     metric.IsLargest,
			},
		}
		updates = append(updates, update)
	}

	log.Printf("[HISTORY] [agent] [storage] Converted %d storage metrics to update items timestamp=%s",
		len(updates), time.Now().Format(time.RFC3339))
	return updates
}

// convertSystemToUpdates converts SystemMetric slices to UpdateReportItem format
func convertSystemToUpdates(metrics []SystemMetric) []client.UpdateReportItem {
	log.Printf("[HISTORY] [agent] [system] converting %d system metrics to update items timestamp=%s",
		len(metrics), time.Now().Format(time.RFC3339))

	updates := make([]client.UpdateReportItem, 0, len(metrics))
	for _, metric := range metrics {
		update := client.UpdateReportItem{
			// Map system metrics to package-like structure for compatibility
			PackageType:        "system",
			PackageName:        metric.MetricName,
			PackageDescription: fmt.Sprintf("System metric %s (%s)", metric.MetricName, metric.MetricType),
			CurrentVersion:     metric.CurrentValue,
			AvailableVersion:   metric.AvailableValue,
			Severity:           metric.Severity,
			RepositorySource:   metric.MetricType,
			Metadata: map[string]interface{}{
				"metric_name":     metric.MetricName,
				"metric_type":     metric.MetricType,
				"current_value":   metric.CurrentValue,
				"available_value": metric.AvailableValue,
			},
		}
		updates = append(updates, update)
	}

	log.Printf("[HISTORY] [agent] [system] Converted %d system metrics to update items timestamp=%s",
		len(updates), time.Now().Format(time.RFC3339))
	return updates
}

// convertDockerToUpdates converts DockerImage slices to UpdateReportItem format
func convertDockerToUpdates(images []DockerImage) []client.UpdateReportItem {
	log.Printf("[HISTORY] [agent] [docker] converting %d docker images to update items timestamp=%s",
		len(images), time.Now().Format(time.RFC3339))

	updates := make([]client.UpdateReportItem, 0, len(images))
	for _, image := range images {
		update := client.UpdateReportItem{
			// Map Docker images to package structure
			PackageType:        "docker",
			PackageName:        image.ImageName,
			PackageDescription: fmt.Sprintf("Docker image %s:%s", image.ImageName, image.ImageTag),
			CurrentVersion:     image.ImageTag,
			AvailableVersion:   "latest",
			Severity:           image.Severity,
			RepositorySource:   image.RepositorySource,
			SizeBytes:          image.SizeBytes,
			Metadata: map[string]interface{}{
				"image_name":     image.ImageName,
				"image_tag":      image.ImageTag,
				"image_id":       image.ImageID,
				"repository":     image.RepositorySource,
				"size_bytes":     image.SizeBytes,
				"created_at":     image.CreatedAt,
				"has_update":     image.HasUpdate,
				"latest_image_id": image.LatestImageID,
				"labels":         image.Labels,
			},
		}
		updates = append(updates, update)
	}

	log.Printf("[HISTORY] [agent] [docker] Converted %d docker images to update items timestamp=%s",
		len(updates), time.Now().Format(time.RFC3339))
	return updates
}

// APTScannerWrapper wraps the APT scanner to implement the Scanner interface
type APTScannerWrapper struct {
	scanner *scanner.APTScanner
}

func NewAPTScannerWrapper(s *scanner.APTScanner) *APTScannerWrapper {
	return &APTScannerWrapper{scanner: s}
}

func (w *APTScannerWrapper) IsAvailable() bool {
	return w.scanner.IsAvailable()
}

func (w *APTScannerWrapper) Scan() ([]client.UpdateReportItem, error) {
	log.Printf("[HISTORY] [agent] [apt] starting scan via wrapper timestamp=%s",
		time.Now().Format(time.RFC3339))

	if w.scanner == nil {
		err := fmt.Errorf("apt scanner is nil")
		log.Printf("[ERROR] [agent] [apt] scan_failed error=\"%v\" timestamp=%s",
			err, time.Now().Format(time.RFC3339))
		return nil, err
	}

	updates, err := w.scanner.Scan()
	if err != nil {
		log.Printf("[ERROR] [agent] [apt] scan_failed error=\"%v\" timestamp=%s",
			err, time.Now().Format(time.RFC3339))
		return nil, err
	}

	log.Printf("[HISTORY] [agent] [apt] scan_completed items=%d timestamp=%s",
		len(updates), time.Now().Format(time.RFC3339))
	return updates, nil
}

func (w *APTScannerWrapper) Name() string {
	return "APT Update Scanner"
}

// DNFScannerWrapper wraps the DNF scanner to implement the Scanner interface
type DNFScannerWrapper struct {
	scanner *scanner.DNFScanner
}

func NewDNFScannerWrapper(s *scanner.DNFScanner) *DNFScannerWrapper {
	return &DNFScannerWrapper{scanner: s}
}

func (w *DNFScannerWrapper) IsAvailable() bool {
	return w.scanner.IsAvailable()
}

func (w *DNFScannerWrapper) Scan() ([]client.UpdateReportItem, error) {
	log.Printf("[HISTORY] [agent] [dnf] starting scan via wrapper timestamp=%s",
		time.Now().Format(time.RFC3339))

	if w.scanner == nil {
		err := fmt.Errorf("dnf scanner is nil")
		log.Printf("[ERROR] [agent] [dnf] scan_failed error=\"%v\" timestamp=%s",
			err, time.Now().Format(time.RFC3339))
		return nil, err
	}

	updates, err := w.scanner.Scan()
	if err != nil {
		log.Printf("[ERROR] [agent] [dnf] scan_failed error=\"%v\" timestamp=%s",
			err, time.Now().Format(time.RFC3339))
		return nil, err
	}

	log.Printf("[HISTORY] [agent] [dnf] scan_completed items=%d timestamp=%s",
		len(updates), time.Now().Format(time.RFC3339))
	return updates, nil
}

func (w *DNFScannerWrapper) Name() string {
	return "DNF Update Scanner"
}

// DockerScannerWrapper wraps the Docker scanner to implement the Scanner interface
type DockerScannerWrapper struct {
	scanner *scanner.DockerScanner
}

func NewDockerScannerWrapper(s *scanner.DockerScanner) *DockerScannerWrapper {
	return &DockerScannerWrapper{scanner: s}
}

func (w *DockerScannerWrapper) IsAvailable() bool {
	if w.scanner == nil {
		return false
	}
	return w.scanner.IsAvailable()
}

func (w *DockerScannerWrapper) Scan() ([]client.UpdateReportItem, error) {
	log.Printf("[HISTORY] [agent] [docker] starting scan via wrapper timestamp=%s",
		time.Now().Format(time.RFC3339))

	if w.scanner == nil {
		err := fmt.Errorf("docker scanner is nil")
		log.Printf("[ERROR] [agent] [docker] scan_failed error=\"%v\" timestamp=%s",
			err, time.Now().Format(time.RFC3339))
		return nil, err
	}

	updates, err := w.scanner.Scan()
	if err != nil {
		log.Printf("[ERROR] [agent] [docker] scan_failed error=\"%v\" timestamp=%s",
			err, time.Now().Format(time.RFC3339))
		return nil, err
	}

	log.Printf("[HISTORY] [agent] [docker] scan_completed items=%d timestamp=%s",
		len(updates), time.Now().Format(time.RFC3339))
	return updates, nil
}

func (w *DockerScannerWrapper) Name() string {
	return "Docker Image Update Scanner"
}

// WindowsUpdateScannerWrapper wraps the Windows Update scanner to implement the Scanner interface
type WindowsUpdateScannerWrapper struct {
	scanner *scanner.WindowsUpdateScanner
}

func NewWindowsUpdateScannerWrapper(s *scanner.WindowsUpdateScanner) *WindowsUpdateScannerWrapper {
	return &WindowsUpdateScannerWrapper{scanner: s}
}

func (w *WindowsUpdateScannerWrapper) IsAvailable() bool {
	return w.scanner.IsAvailable()
}

func (w *WindowsUpdateScannerWrapper) Scan() ([]client.UpdateReportItem, error) {
	log.Printf("[HISTORY] [agent] [windows] starting scan via wrapper timestamp=%s",
		time.Now().Format(time.RFC3339))

	if w.scanner == nil {
		err := fmt.Errorf("windows update scanner is nil")
		log.Printf("[ERROR] [agent] [windows] scan_failed error=\"%v\" timestamp=%s",
			err, time.Now().Format(time.RFC3339))
		return nil, err
	}

	updates, err := w.scanner.Scan()
	if err != nil {
		log.Printf("[ERROR] [agent] [windows] scan_failed error=\"%v\" timestamp=%s",
			err, time.Now().Format(time.RFC3339))
		return nil, err
	}

	log.Printf("[HISTORY] [agent] [windows] scan_completed items=%d timestamp=%s",
		len(updates), time.Now().Format(time.RFC3339))
	return updates, nil
}

func (w *WindowsUpdateScannerWrapper) Name() string {
	return "Windows Update Scanner"
}

// WingetScannerWrapper wraps the Winget scanner to implement the Scanner interface
type WingetScannerWrapper struct {
	scanner *scanner.WingetScanner
}

func NewWingetScannerWrapper(s *scanner.WingetScanner) *WingetScannerWrapper {
	return &WingetScannerWrapper{scanner: s}
}

func (w *WingetScannerWrapper) IsAvailable() bool {
	return w.scanner.IsAvailable()
}

func (w *WingetScannerWrapper) Scan() ([]client.UpdateReportItem, error) {
	log.Printf("[HISTORY] [agent] [winget] starting scan via wrapper timestamp=%s",
		time.Now().Format(time.RFC3339))

	if w.scanner == nil {
		err := fmt.Errorf("winget scanner is nil")
		log.Printf("[ERROR] [agent] [winget] scan_failed error=\"%v\" timestamp=%s",
			err, time.Now().Format(time.RFC3339))
		return nil, err
	}

	updates, err := w.scanner.Scan()
	if err != nil {
		log.Printf("[ERROR] [agent] [winget] scan_failed error=\"%v\" timestamp=%s",
			err, time.Now().Format(time.RFC3339))
		return nil, err
	}

	log.Printf("[HISTORY] [agent] [winget] scan_completed items=%d timestamp=%s",
		len(updates), time.Now().Format(time.RFC3339))
	return updates, nil
}

func (w *WingetScannerWrapper) Name() string {
	return "Winget Package Update Scanner"
}

// StorageScannerWrapper wraps the Storage scanner to implement the Scanner interface
type StorageScannerWrapper struct {
	scanner *StorageScanner
}

func NewStorageScannerWrapper(s *StorageScanner) *StorageScannerWrapper {
	return &StorageScannerWrapper{scanner: s}
}

func (w *StorageScannerWrapper) IsAvailable() bool {
	return w.scanner.IsAvailable()
}

func (w *StorageScannerWrapper) Scan() ([]client.UpdateReportItem, error) {
	log.Printf("[HISTORY] [agent] [storage] starting scan via wrapper timestamp=%s",
		time.Now().Format(time.RFC3339))

	if w.scanner == nil {
		err := fmt.Errorf("storage scanner is nil")
		log.Printf("[ERROR] [agent] [storage] scan failed error=\"%v\" timestamp=%s",
			err, time.Now().Format(time.RFC3339))
		return nil, err
	}

	metrics, err := w.scanner.ScanStorage()
	if err != nil {
		log.Printf("[ERROR] [agent] [storage] scan_failed error=\"%v\" timestamp=%s",
			err, time.Now().Format(time.RFC3339))
		return nil, err
	}

	updates := convertStorageToUpdates(metrics)

	log.Printf("[HISTORY] [agent] [storage] scan_completed items=%d timestamp=%s",
		len(updates), time.Now().Format(time.RFC3339))
	return updates, nil
}

func (w *StorageScannerWrapper) Name() string {
	return w.scanner.Name()
}

// SystemScannerWrapper wraps the System scanner to implement the Scanner interface
type SystemScannerWrapper struct {
	scanner *SystemScanner
}

func NewSystemScannerWrapper(s *SystemScanner) *SystemScannerWrapper {
	return &SystemScannerWrapper{scanner: s}
}

func (w *SystemScannerWrapper) IsAvailable() bool {
	return w.scanner.IsAvailable()
}

func (w *SystemScannerWrapper) Scan() ([]client.UpdateReportItem, error) {
	log.Printf("[HISTORY] [agent] [system] starting scan via wrapper timestamp=%s",
		time.Now().Format(time.RFC3339))

	if w.scanner == nil {
		err := fmt.Errorf("system scanner is nil")
		log.Printf("[ERROR] [agent] [system] scan_failed error=\"%v\" timestamp=%s",
			err, time.Now().Format(time.RFC3339))
		return nil, err
	}

	metrics, err := w.scanner.ScanSystem()
	if err != nil {
		log.Printf("[ERROR] [agent] [system] scan_failed error=\"%v\" timestamp=%s",
			err, time.Now().Format(time.RFC3339))
		return nil, err
	}

	updates := convertSystemToUpdates(metrics)

	log.Printf("[HISTORY] [agent] [system] scan_completed items=%d timestamp=%s",
		len(updates), time.Now().Format(time.RFC3339))
	return updates, nil
}

func (w *SystemScannerWrapper) Name() string {
	return w.scanner.Name()
}
