package services

import (
	"fmt"

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

// TemplateService handles business logic for templates
type TemplateService struct {
	store *dbstore.TemplateStore
}

// NewTemplateService creates a new TemplateService
func NewTemplateService(store *dbstore.TemplateStore) *TemplateService {
	return &TemplateService{store: store}
}

// CreateTemplate creates a new deployment template
func (s *TemplateService) CreateTemplate(template *models.Template) error {
	// Generate UUID if not provided
	if template.ID == "" {
		template.ID = uuid.New().String()
	}

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

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

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

// UpdateTemplate updates an existing template
func (s *TemplateService) UpdateTemplate(template *models.Template) error {
	if template.ID == "" {
		return fmt.Errorf("template ID is required for update")
	}

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

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

	return s.store.Update(template)
}

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

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

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

	return s.store.Delete(id)
}

// ListTemplates retrieves all templates with optional filtering
func (s *TemplateService) ListTemplates(filter map[string]interface{}) ([]*models.Template, error) {
	return s.store.List(filter)
}

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

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

	return templateWithDeployments.Deployments, nil
}

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

// validateTemplateConfig validates the template configuration
func validateTemplateConfig(config models.TemplateConfig) error {
	// Validate that at least one app is defined
	if len(config.Apps) == 0 {
		return fmt.Errorf("template must define at least one app")
	}

	// Validate each app in the template
	for i, app := range config.Apps {
		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
}
