package system

import (
	"context"
	"encoding/json"
	"fmt"
	"os/exec"
	"strings"
	"time"

	"github.com/atlasos/calypso/internal/common/logger"
)

// Service handles system management operations
type Service struct {
	logger *logger.Logger
}

// NewService creates a new system service
func NewService(log *logger.Logger) *Service {
	return &Service{
		logger: log,
	}
}

// ServiceStatus represents a systemd service status
type ServiceStatus struct {
	Name        string    `json:"name"`
	ActiveState string    `json:"active_state"`
	SubState    string    `json:"sub_state"`
	LoadState   string    `json:"load_state"`
	Description string    `json:"description"`
	Since       time.Time `json:"since,omitempty"`
}

// GetServiceStatus retrieves the status of a systemd service
func (s *Service) GetServiceStatus(ctx context.Context, serviceName string) (*ServiceStatus, error) {
	cmd := exec.CommandContext(ctx, "systemctl", "show", serviceName,
		"--property=ActiveState,SubState,LoadState,Description,ActiveEnterTimestamp",
		"--value", "--no-pager")
	output, err := cmd.Output()
	if err != nil {
		return nil, fmt.Errorf("failed to get service status: %w", err)
	}

	lines := strings.Split(strings.TrimSpace(string(output)), "\n")
	if len(lines) < 4 {
		return nil, fmt.Errorf("invalid service status output")
	}

	status := &ServiceStatus{
		Name:        serviceName,
		ActiveState: strings.TrimSpace(lines[0]),
		SubState:    strings.TrimSpace(lines[1]),
		LoadState:   strings.TrimSpace(lines[2]),
		Description: strings.TrimSpace(lines[3]),
	}

	// Parse timestamp if available
	if len(lines) > 4 && lines[4] != "" {
		if t, err := time.Parse("Mon 2006-01-02 15:04:05 MST", strings.TrimSpace(lines[4])); err == nil {
			status.Since = t
		}
	}

	return status, nil
}

// ListServices lists all Calypso-related services
func (s *Service) ListServices(ctx context.Context) ([]ServiceStatus, error) {
	services := []string{
		"calypso-api",
		"scst",
		"iscsi-scst",
		"mhvtl",
		"postgresql",
	}

	var statuses []ServiceStatus
	for _, serviceName := range services {
		status, err := s.GetServiceStatus(ctx, serviceName)
		if err != nil {
			s.logger.Warn("Failed to get service status", "service", serviceName, "error", err)
			continue
		}
		statuses = append(statuses, *status)
	}

	return statuses, nil
}

// RestartService restarts a systemd service
func (s *Service) RestartService(ctx context.Context, serviceName string) error {
	cmd := exec.CommandContext(ctx, "systemctl", "restart", serviceName)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("failed to restart service: %s: %w", string(output), err)
	}

	s.logger.Info("Service restarted", "service", serviceName)
	return nil
}

// GetJournalLogs retrieves journald logs for a service
func (s *Service) GetJournalLogs(ctx context.Context, serviceName string, lines int) ([]map[string]interface{}, error) {
	cmd := exec.CommandContext(ctx, "journalctl",
		"-u", serviceName,
		"-n", fmt.Sprintf("%d", lines),
		"-o", "json",
		"--no-pager")
	output, err := cmd.Output()
	if err != nil {
		return nil, fmt.Errorf("failed to get logs: %w", err)
	}

	var logs []map[string]interface{}
	linesOutput := strings.Split(strings.TrimSpace(string(output)), "\n")
	for _, line := range linesOutput {
		if line == "" {
			continue
		}
		var logEntry map[string]interface{}
		if err := json.Unmarshal([]byte(line), &logEntry); err == nil {
			logs = append(logs, logEntry)
		}
	}

	return logs, nil
}

// GenerateSupportBundle generates a diagnostic support bundle
func (s *Service) GenerateSupportBundle(ctx context.Context, outputPath string) error {
	// Create bundle directory
	cmd := exec.CommandContext(ctx, "mkdir", "-p", outputPath)
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("failed to create bundle directory: %w", err)
	}

	// Collect system information
	commands := map[string][]string{
		"system_info": {"uname", "-a"},
		"disk_usage":  {"df", "-h"},
		"memory":      {"free", "-h"},
		"scst_status": {"scstadmin", "-list_target"},
		"services":    {"systemctl", "list-units", "--type=service", "--state=running"},
	}

	for name, cmdArgs := range commands {
		cmd := exec.CommandContext(ctx, cmdArgs[0], cmdArgs[1:]...)
		output, err := cmd.CombinedOutput()
		if err != nil {
			s.logger.Warn("Failed to collect info", "command", name, "error", err)
			continue
		}

		// Write to file
		filePath := fmt.Sprintf("%s/%s.txt", outputPath, name)
		if err := exec.CommandContext(ctx, "sh", "-c", fmt.Sprintf("cat > %s", filePath)).Run(); err == nil {
			exec.CommandContext(ctx, "sh", "-c", fmt.Sprintf("echo '%s' > %s", string(output), filePath)).Run()
		}
	}

	// Collect journal logs
	services := []string{"calypso-api", "scst", "iscsi-scst"}
	for _, service := range services {
		cmd := exec.CommandContext(ctx, "journalctl", "-u", service, "-n", "1000", "--no-pager")
		output, err := cmd.CombinedOutput()
		if err == nil {
			filePath := fmt.Sprintf("%s/journal_%s.log", outputPath, service)
			exec.CommandContext(ctx, "sh", "-c", fmt.Sprintf("echo '%s' > %s", string(output), filePath)).Run()
		}
	}

	s.logger.Info("Support bundle generated", "path", outputPath)
	return nil
}

