package templates

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"sync"
	"time"

	"gopkg.in/yaml.v3"
)

// WorkflowTemplate defines the structure of a workflow template
type WorkflowTemplate struct {
	// Metadata
	Name        string `yaml:"name" json:"name"`
	Version     string `yaml:"version" json:"version"`
	Description string `yaml:"description" json:"description"`
	Author      string `yaml:"author" json:"author"`
	CreatedAt   time.Time `yaml:"created_at" json:"created_at"`
	UpdatedAt   time.Time `yaml:"updated_at" json:"updated_at"`

	// Orchestrator Configuration
	Orchestrator OrchestratorConfig `yaml:"orchestrator" json:"orchestrator"`

	// Task Configuration
	Tasks []TaskConfig `yaml:"tasks" json:"tasks"`

	// Variable Defaults
	Defaults map[string]interface{} `yaml:"defaults" json:"defaults,omitempty"`

	// Tags and Metadata
	Tags map[string]string `yaml:"tags" json:"tags,omitempty"`
}

// OrchestratorConfig defines orchestrator settings
type OrchestratorConfig struct {
	PlannerURL       string            `yaml:"planner_url" json:"planner_url"`
	JudgeURL         string            `yaml:"judge_url" json:"judge_url"`
	ImplementerURL   string            `yaml:"implementer_url" json:"implementer_url"`
	TimeoutSeconds   int               `yaml:"timeout_seconds" json:"timeout_seconds"`
	RetryPolicy      string            `yaml:"retry_policy" json:"retry_policy"`
	MaxConcurrency   int               `yaml:"max_concurrency" json:"max_concurrency"`
	Variables        map[string]interface{} `yaml:"variables" json:"variables,omitempty"`
}

// TaskConfig defines task template
type TaskConfig struct {
	ID          string                 `yaml:"id" json:"id"`
	Title       string                 `yaml:"title" json:"title"`
	Description string                 `yaml:"description" json:"description"`
	Type        string                 `yaml:"type" json:"type"` // feature, bugfix, refactor, etc.
	Priority    string                 `yaml:"priority" json:"priority"` // high, medium, low
	DependsOn   []string               `yaml:"depends_on" json:"depends_on,omitempty"`
	Config      map[string]interface{} `yaml:"config" json:"config,omitempty"`
}

// WorkflowTemplateManager manages workflow templates
type WorkflowTemplateManager struct {
	mu            sync.RWMutex
	templates     map[string]*WorkflowTemplate
	templatePath  string
	loadedFrom    map[string]string // template name -> file path
	lastModified  map[string]time.Time
	stats         *TemplateStats
}

// TemplateStats tracks template usage
type TemplateStats struct {
	TotalTemplates    int
	LoadedTemplates   int
	ExecutedTemplates int
	LastUsed          map[string]time.Time
}

// NewWorkflowTemplateManager creates a new template manager
func NewWorkflowTemplateManager(templatePath string) *WorkflowTemplateManager {
	return &WorkflowTemplateManager{
		templates:    make(map[string]*WorkflowTemplate),
		templatePath: templatePath,
		loadedFrom:   make(map[string]string),
		lastModified: make(map[string]time.Time),
		stats: &TemplateStats{
			LastUsed: make(map[string]time.Time),
		},
	}
}

// SaveTemplate saves a template to file
func (wtm *WorkflowTemplateManager) SaveTemplate(template *WorkflowTemplate) error {
	if template == nil {
		return fmt.Errorf("template cannot be nil")
	}

	if template.Name == "" {
		return fmt.Errorf("template name cannot be empty")
	}

	wtm.mu.Lock()
	defer wtm.mu.Unlock()

	// Update timestamps
	now := time.Now()
	template.UpdatedAt = now
	if template.CreatedAt.IsZero() {
		template.CreatedAt = now
	}

	// Create directory if needed
	if err := os.MkdirAll(wtm.templatePath, 0755); err != nil {
		return err
	}

	// Save to YAML file
	filePath := filepath.Join(wtm.templatePath, template.Name+".yaml")
	data, err := yaml.Marshal(template)
	if err != nil {
		return err
	}

	if err := os.WriteFile(filePath, data, 0644); err != nil {
		return err
	}

	// Update tracking
	wtm.templates[template.Name] = template
	wtm.loadedFrom[template.Name] = filePath
	wtm.lastModified[template.Name] = now
	wtm.stats.TotalTemplates++
	wtm.stats.LoadedTemplates++

	return nil
}

// LoadTemplate loads a template from file
func (wtm *WorkflowTemplateManager) LoadTemplate(name string) (*WorkflowTemplate, error) {
	wtm.mu.Lock()
	defer wtm.mu.Unlock()

	// Check if already loaded
	if template, exists := wtm.templates[name]; exists {
		return template, nil
	}

	// Try to load from file
	filePath := filepath.Join(wtm.templatePath, name+".yaml")
	data, err := os.ReadFile(filePath)
	if err != nil {
		return nil, fmt.Errorf("failed to read template: %w", err)
	}

	var template WorkflowTemplate
	if err := yaml.Unmarshal(data, &template); err != nil {
		return nil, fmt.Errorf("failed to parse template: %w", err)
	}

	// Cache the template
	wtm.templates[name] = &template
	wtm.loadedFrom[name] = filePath
	wtm.lastModified[name] = time.Now()
	wtm.stats.LoadedTemplates++
	wtm.stats.TotalTemplates++

	return &template, nil
}

// LoadTemplateDirectory loads all templates from a directory
func (wtm *WorkflowTemplateManager) LoadTemplateDirectory() error {
	entries, err := os.ReadDir(wtm.templatePath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil // Directory doesn't exist yet
		}
		return err
	}

	for _, entry := range entries {
		if !entry.IsDir() && filepath.Ext(entry.Name()) == ".yaml" {
			name := entry.Name()[:len(entry.Name())-5] // Remove .yaml
			_, _ = wtm.LoadTemplate(name)
		}
	}

	return nil
}

// GetTemplate retrieves a cached template
func (wtm *WorkflowTemplateManager) GetTemplate(name string) (*WorkflowTemplate, bool) {
	wtm.mu.RLock()
	defer wtm.mu.RUnlock()

	template, exists := wtm.templates[name]
	return template, exists
}

// ListTemplates returns all loaded templates
func (wtm *WorkflowTemplateManager) ListTemplates() map[string]*WorkflowTemplate {
	wtm.mu.RLock()
	defer wtm.mu.RUnlock()

	result := make(map[string]*WorkflowTemplate)
	for name, template := range wtm.templates {
		result[name] = template
	}

	return result
}

// DeleteTemplate deletes a template
func (wtm *WorkflowTemplateManager) DeleteTemplate(name string) error {
	wtm.mu.Lock()
	defer wtm.mu.Unlock()

	filePath, exists := wtm.loadedFrom[name]
	if !exists {
		return fmt.Errorf("template not found: %s", name)
	}

	if err := os.Remove(filePath); err != nil && !os.IsNotExist(err) {
		return err
	}

	delete(wtm.templates, name)
	delete(wtm.loadedFrom, name)
	delete(wtm.lastModified, name)

	return nil
}

// ExportTemplateJSON exports a template as JSON
func (wtm *WorkflowTemplateManager) ExportTemplateJSON(name string) (string, error) {
	wtm.mu.RLock()
	template, exists := wtm.templates[name]
	wtm.mu.RUnlock()

	if !exists {
		return "", fmt.Errorf("template not found: %s", name)
	}

	data, err := json.MarshalIndent(template, "", "  ")
	if err != nil {
		return "", err
	}

	return string(data), nil
}

// ValidateTemplate validates a template
func (wtm *WorkflowTemplateManager) ValidateTemplate(template *WorkflowTemplate) error {
	if template.Name == "" {
		return fmt.Errorf("template name is required")
	}

	if template.Orchestrator.PlannerURL == "" {
		return fmt.Errorf("planner_url is required")
	}

	if len(template.Tasks) == 0 {
		return fmt.Errorf("at least one task is required")
	}

	// Validate task dependencies
	taskIDs := make(map[string]bool)
	for _, task := range template.Tasks {
		if task.ID == "" {
			return fmt.Errorf("task ID is required")
		}
		taskIDs[task.ID] = true
	}

	for _, task := range template.Tasks {
		for _, dep := range task.DependsOn {
			if !taskIDs[dep] {
				return fmt.Errorf("task %s depends on non-existent task %s", task.ID, dep)
			}
		}
	}

	return nil
}

// RecordUsage records template usage
func (wtm *WorkflowTemplateManager) RecordUsage(name string) error {
	wtm.mu.Lock()
	defer wtm.mu.Unlock()

	if _, exists := wtm.templates[name]; !exists {
		return fmt.Errorf("template not found: %s", name)
	}

	wtm.stats.ExecutedTemplates++
	wtm.stats.LastUsed[name] = time.Now()

	return nil
}

// GetStats returns template manager statistics
func (wtm *WorkflowTemplateManager) GetStats() *TemplateStats {
	wtm.mu.RLock()
	defer wtm.mu.RUnlock()

	stats := *wtm.stats
	return &stats
}

// ClearCache clears all cached templates
func (wtm *WorkflowTemplateManager) ClearCache() {
	wtm.mu.Lock()
	defer wtm.mu.Unlock()

	wtm.templates = make(map[string]*WorkflowTemplate)
	wtm.loadedFrom = make(map[string]string)
	wtm.lastModified = make(map[string]time.Time)
}
