package services

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/Fimeg/RedFlag/aggregator-server/internal/database/queries"
	"github.com/Fimeg/RedFlag/aggregator-server/internal/models"
	"github.com/google/uuid"
)

// BuildOrchestratorService handles building and signing agent binaries
type BuildOrchestratorService struct {
	signingService *SigningService
	packageQueries *queries.PackageQueries
	agentDir       string // Directory containing pre-built binaries
}

// NewBuildOrchestratorService creates a new build orchestrator service
func NewBuildOrchestratorService(signingService *SigningService, packageQueries *queries.PackageQueries, agentDir string) *BuildOrchestratorService {
	return &BuildOrchestratorService{
		signingService: signingService,
		packageQueries: packageQueries,
		agentDir:       agentDir,
	}
}

// BuildAndSignAgent builds (or retrieves) and signs an agent binary
func (s *BuildOrchestratorService) BuildAndSignAgent(version, platform, architecture string) (*models.AgentUpdatePackage, error) {
	// Determine binary name
	binaryName := "redflag-agent"
	if strings.HasPrefix(platform, "windows") {
		binaryName += ".exe"
	}

	// Path to pre-built binary
	binaryPath := filepath.Join(s.agentDir, "binaries", platform, binaryName)

	// Check if binary exists
	if _, err := os.Stat(binaryPath); os.IsNotExist(err) {
		return nil, fmt.Errorf("binary not found for platform %s: %w", platform, err)
	}

	// Sign the binary if signing is enabled
	if s.signingService.IsEnabled() {
		signedPackage, err := s.signingService.SignFile(binaryPath)
		if err != nil {
			return nil, fmt.Errorf("failed to sign agent binary: %w", err)
		}

		// Set additional fields
		signedPackage.Version = version
		signedPackage.Platform = platform
		signedPackage.Architecture = architecture

		// Store signed package in database
		err = s.packageQueries.StoreSignedPackage(signedPackage)
		if err != nil {
			return nil, fmt.Errorf("failed to store signed package: %w", err)
		}

		log.Printf("Successfully signed and stored agent binary: %s (%s/%s)", signedPackage.ID, platform, architecture)
		return signedPackage, nil
	} else {
		log.Printf("Signing disabled, creating unsigned package entry")
		// Create unsigned package entry for backward compatibility
		unsignedPackage := &models.AgentUpdatePackage{
			ID:           uuid.New(),
			Version:      version,
			Platform:     platform,
			Architecture: architecture,
			BinaryPath:   binaryPath,
			Signature:    "",
			Checksum:     "", // Would need to calculate if needed
			FileSize:     0,  // Would need to stat if needed
			CreatedBy:    "build-orchestrator",
			IsActive:     true,
		}

		// Get file info
		if info, err := os.Stat(binaryPath); err == nil {
			unsignedPackage.FileSize = info.Size()
		}

		// Store unsigned package
		err := s.packageQueries.StoreSignedPackage(unsignedPackage)
		if err != nil {
			return nil, fmt.Errorf("failed to store unsigned package: %w", err)
		}

		return unsignedPackage, nil
	}
}

// SignExistingBinary signs an existing binary file
func (s *BuildOrchestratorService) SignExistingBinary(binaryPath, version, platform, architecture string) (*models.AgentUpdatePackage, error) {
	// Check if file exists
	if _, err := os.Stat(binaryPath); os.IsNotExist(err) {
		return nil, fmt.Errorf("binary not found: %s", binaryPath)
	}

	// Sign the binary if signing is enabled
	if !s.signingService.IsEnabled() {
		return nil, fmt.Errorf("signing service is disabled")
	}

	signedPackage, err := s.signingService.SignFile(binaryPath)
	if err != nil {
		return nil, fmt.Errorf("failed to sign agent binary: %w", err)
	}

	// Set additional fields
	signedPackage.Version = version
	signedPackage.Platform = platform
	signedPackage.Architecture = architecture

	// Store signed package in database
	err = s.packageQueries.StoreSignedPackage(signedPackage)
	if err != nil {
		return nil, fmt.Errorf("failed to store signed package: %w", err)
	}

	log.Printf("Successfully signed and stored agent binary: %s (%s/%s)", signedPackage.ID, platform, architecture)
	return signedPackage, nil
}

// GetSignedPackage retrieves a signed package by version and platform
func (s *BuildOrchestratorService) GetSignedPackage(version, platform, architecture string) (*models.AgentUpdatePackage, error) {
	return s.packageQueries.GetSignedPackage(version, platform, architecture)
}

// ListSignedPackages lists all signed packages (with optional filters)
func (s *BuildOrchestratorService) ListSignedPackages(version, platform string, limit, offset int) ([]models.AgentUpdatePackage, error) {
	return s.packageQueries.ListUpdatePackages(version, platform, limit, offset)
}