package services

import (
	"fmt"

	"git.linuxforward.com/byop/byop-engine/dbstore"
	"git.linuxforward.com/byop/byop-engine/models"
	"github.com/google/uuid"
)

// BlueprintService handles business logic for Blueprints
type BlueprintService struct {
	store *dbstore.BlueprintStore
}

// NewBlueprintService creates a new BlueprintService
func NewBlueprintService(store *dbstore.BlueprintStore) *BlueprintService {
	return &BlueprintService{store: store}
}

// CreateBlueprint creates a new deployment Blueprint
func (s *BlueprintService) CreateBlueprint(Blueprint *models.Blueprint) error {
	// Generate UUID if not provided
	if Blueprint.ID == "" {
		Blueprint.ID = uuid.New().String()
	}

	// Validate Blueprint configuration
	if err := validateBlueprintConfig(Blueprint.Config); err != nil {
		return fmt.Errorf("invalid Blueprint configuration: %w", err)
	}

	// Persist the Blueprint
	return s.store.Create(Blueprint)
}

// GetBlueprint retrieves a Blueprint by ID
func (s *BlueprintService) GetBlueprint(id string) (*models.Blueprint, error) {
	Blueprint, err := s.store.GetByID(id)
	if err != nil {
		return nil, fmt.Errorf("failed to retrieve Blueprint: %w", err)
	}
	return Blueprint, nil
}

// UpdateBlueprint updates an existing Blueprint
func (s *BlueprintService) UpdateBlueprint(Blueprint *models.Blueprint) error {
	if Blueprint.ID == "" {
		return fmt.Errorf("Blueprint ID is required for update")
	}

	// Check if Blueprint exists
	existingBlueprint, err := s.store.GetByID(Blueprint.ID)
	if err != nil {
		return fmt.Errorf("failed to check if Blueprint exists: %w", err)
	}
	if existingBlueprint == nil {
		return fmt.Errorf("Blueprint with ID %s not found", Blueprint.ID)
	}

	// Validate Blueprint configuration
	if err := validateBlueprintConfig(Blueprint.Config); err != nil {
		return fmt.Errorf("invalid Blueprint configuration: %w", err)
	}

	return s.store.Update(Blueprint)
}

// DeleteBlueprint deletes a Blueprint by ID
func (s *BlueprintService) DeleteBlueprint(id string) error {
	// Check if Blueprint exists
	Blueprint, err := s.store.GetByID(id)
	if err != nil {
		return fmt.Errorf("failed to check if Blueprint exists: %w", err)
	}
	if Blueprint == nil {
		return fmt.Errorf("Blueprint with ID %s not found", id)
	}

	// Check if the Blueprint has deployments
	BlueprintWithDeployments, err := s.store.GetBlueprintWithDeployments(id)
	if err != nil {
		return fmt.Errorf("failed to check Blueprint deployments: %w", err)
	}

	// Don't allow deletion if there are active deployments
	if len(BlueprintWithDeployments.Deployments) > 0 {
		return fmt.Errorf("cannot delete Blueprint with active deployments")
	}

	return s.store.Delete(id)
}

// ListBlueprints retrieves all Blueprints with optional filtering
func (s *BlueprintService) ListBlueprints(filter map[string]interface{}) ([]*models.Blueprint, error) {
	return s.store.List(filter)
}

// GetBlueprintDeployments retrieves all deployments for a Blueprint
func (s *BlueprintService) GetBlueprintDeployments(id string) ([]models.Deployment, error) {
	// First check if the Blueprint exists
	Blueprint, err := s.store.GetByID(id)
	if err != nil {
		return nil, fmt.Errorf("failed to check if Blueprint exists: %w", err)
	}
	if Blueprint == nil {
		return nil, fmt.Errorf("Blueprint with ID %s not found", id)
	}

	// Get Blueprint with deployments
	BlueprintWithDeployments, err := s.store.GetBlueprintWithDeployments(id)
	if err != nil {
		return nil, fmt.Errorf("failed to retrieve Blueprint deployments: %w", err)
	}

	return BlueprintWithDeployments.Deployments, nil
}

// GetBlueprintByVersion retrieves a Blueprint by name and version
func (s *BlueprintService) GetBlueprintByVersion(name, version string) (*models.Blueprint, error) {
	Blueprint, err := s.store.GetByVersion(name, version)
	if err != nil {
		return nil, fmt.Errorf("failed to retrieve Blueprint: %w", err)
	}
	return Blueprint, nil
}

// validateBlueprintConfig validates the Blueprint configuration
func validateBlueprintConfig(config models.BlueprintConfig) error {
	// Validate that at least one app is defined
	if len(config.Components) == 0 {
		return fmt.Errorf("Blueprint must define at least one app")
	}

	// Validate each app in the Blueprint
	for i, app := range config.Components {
		if app.Name == "" {
			return fmt.Errorf("app at index %d must have a name", i)
		}

		// Validate resource configuration
		if app.Resources.CPU == "" {
			return fmt.Errorf("app '%s' must specify CPU resources", app.Name)
		}
		if app.Resources.Memory == "" {
			return fmt.Errorf("app '%s' must specify memory resources", app.Name)
		}
	}

	// Add additional validation logic as needed

	return nil
}
