package profiling

import (
	"fmt"
	"sort"
	"sync"
)

// TaskProfile represents profiling data for a task
type TaskProfile struct {
	TaskID    string
	Duration  float64
	CPUUsage  float64
	MemUsage  float64
	Throughput float64
}

// WorkflowProfile represents profiling for an entire workflow
type WorkflowProfile struct {
	WorkflowID    string
	Tasks         map[string]*TaskProfile
	TotalDuration float64
	CriticalPath  []string
}

// WorkflowProfiler profiles workflow execution
type WorkflowProfiler struct {
	mu        sync.RWMutex
	profiles  map[string]*WorkflowProfile
}

// NewWorkflowProfiler creates a new workflow profiler
func NewWorkflowProfiler() *WorkflowProfiler {
	return &WorkflowProfiler{
		profiles: make(map[string]*WorkflowProfile),
	}
}

// RecordTaskExecution records task execution metrics
func (wp *WorkflowProfiler) RecordTaskExecution(workflowID, taskID string, duration, cpu, mem float64) {
	wp.mu.Lock()
	defer wp.mu.Unlock()

	if _, exists := wp.profiles[workflowID]; !exists {
		wp.profiles[workflowID] = &WorkflowProfile{
			WorkflowID:   workflowID,
			Tasks:        make(map[string]*TaskProfile),
			CriticalPath: make([]string, 0),
		}
	}

	profile := wp.profiles[workflowID]
	profile.Tasks[taskID] = &TaskProfile{
		TaskID:    taskID,
		Duration:  duration,
		CPUUsage:  cpu,
		MemUsage:  mem,
		Throughput: 1000.0 / duration, // Tasks per second
	}

	// Recalculate total duration
	total := 0.0
	for _, tp := range profile.Tasks {
		if tp.Duration > total {
			total = tp.Duration
		}
	}
	profile.TotalDuration = total
}

// GetSlowTasks returns tasks sorted by duration (slowest first)
func (wp *WorkflowProfiler) GetSlowTasks(workflowID string, limit int) []string {
	wp.mu.RLock()
	defer wp.mu.RUnlock()

	profile, exists := wp.profiles[workflowID]
	if !exists {
		return []string{}
	}

	// Sort tasks by duration
	type taskDuration struct {
		taskID   string
		duration float64
	}

	tasks := make([]taskDuration, 0)
	for taskID, tp := range profile.Tasks {
		tasks = append(tasks, taskDuration{taskID, tp.Duration})
	}

	sort.Slice(tasks, func(i, j int) bool {
		return tasks[i].duration > tasks[j].duration
	})

	result := make([]string, 0)
	for i, t := range tasks {
		if i >= limit {
			break
		}
		result = append(result, t.taskID)
	}

	return result
}

// GetHighCPUTasks returns tasks with high CPU usage
func (wp *WorkflowProfiler) GetHighCPUTasks(workflowID string, threshold float64) []string {
	wp.mu.RLock()
	defer wp.mu.RUnlock()

	profile, exists := wp.profiles[workflowID]
	if !exists {
		return []string{}
	}

	result := make([]string, 0)
	for taskID, tp := range profile.Tasks {
		if tp.CPUUsage > threshold {
			result = append(result, taskID)
		}
	}

	return result
}

// GetHighMemTasks returns tasks with high memory usage
func (wp *WorkflowProfiler) GetHighMemTasks(workflowID string, threshold float64) []string {
	wp.mu.RLock()
	defer wp.mu.RUnlock()

	profile, exists := wp.profiles[workflowID]
	if !exists {
		return []string{}
	}

	result := make([]string, 0)
	for taskID, tp := range profile.Tasks {
		if tp.MemUsage > threshold {
			result = append(result, taskID)
		}
	}

	return result
}

// GetOptimizationSuggestions returns optimization recommendations
func (wp *WorkflowProfiler) GetOptimizationSuggestions(workflowID string) []string {
	wp.mu.RLock()
	defer wp.mu.RUnlock()

	profile, exists := wp.profiles[workflowID]
	if !exists {
		return []string{}
	}

	suggestions := make([]string, 0)

	// Check for slow tasks
	for taskID, tp := range profile.Tasks {
		if tp.Duration > profile.TotalDuration*0.5 {
			suggestions = append(suggestions, fmt.Sprintf("Task %s takes 50%% of total time, consider optimizing", taskID))
		}
		if tp.CPUUsage > 0.8 {
			suggestions = append(suggestions, fmt.Sprintf("Task %s has high CPU usage (%.2f), consider parallelizing", taskID, tp.CPUUsage))
		}
		if tp.MemUsage > 0.8 {
			suggestions = append(suggestions, fmt.Sprintf("Task %s has high memory usage (%.2f), consider reducing payload", taskID, tp.MemUsage))
		}
	}

	return suggestions
}

// GetProfile retrieves profiling data for a workflow
func (wp *WorkflowProfiler) GetProfile(workflowID string) (*WorkflowProfile, bool) {
	wp.mu.RLock()
	defer wp.mu.RUnlock()

	profile, exists := wp.profiles[workflowID]
	return profile, exists
}

// GetTaskProfile retrieves profiling data for a specific task
func (wp *WorkflowProfiler) GetTaskProfile(workflowID, taskID string) (*TaskProfile, error) {
	wp.mu.RLock()
	defer wp.mu.RUnlock()

	profile, exists := wp.profiles[workflowID]
	if !exists {
		return nil, fmt.Errorf("workflow not found: %s", workflowID)
	}

	taskProfile, exists := profile.Tasks[taskID]
	if !exists {
		return nil, fmt.Errorf("task not found: %s", taskID)
	}

	return taskProfile, nil
}

// Clear clears all profiles
func (wp *WorkflowProfiler) Clear() {
	wp.mu.Lock()
	defer wp.mu.Unlock()

	wp.profiles = make(map[string]*WorkflowProfile)
}
