package cost

import (
	"fmt"
	"sync"
	"time"
)

// CostEntry represents a tracked cost
type CostEntry struct {
	ID        string
	Type      string // llm, git, compute
	WorkflowID string
	TaskID    string
	Amount    float64
	Timestamp time.Time
	Metadata  map[string]interface{}
}

// CostTracker tracks and analyzes workflow costs
type CostTracker struct {
	mu       sync.RWMutex
	entries  []*CostEntry
	rates    map[string]float64
}

// NewCostTracker creates a new cost tracker
func NewCostTracker() *CostTracker {
	return &CostTracker{
		entries: make([]*CostEntry, 0),
		rates: map[string]float64{
			"llm_token":     0.0001,  // $0.0001 per token
			"git_push":      0.0,     // Free
			"compute_hour":  0.5,     // $0.5 per hour
		},
	}
}

// TrackLLMCost tracks LLM API costs
func (ct *CostTracker) TrackLLMCost(workflowID, taskID string, tokens int) {
	cost := float64(tokens) * ct.rates["llm_token"]
	ct.mu.Lock()
	defer ct.mu.Unlock()

	entry := &CostEntry{
		ID:         fmt.Sprintf("llm-%d", len(ct.entries)),
		Type:       "llm",
		WorkflowID: workflowID,
		TaskID:     taskID,
		Amount:     cost,
		Timestamp:  time.Now(),
		Metadata: map[string]interface{}{
			"tokens": tokens,
		},
	}

	ct.entries = append(ct.entries, entry)
}

// TrackGitCost tracks git operation costs
func (ct *CostTracker) TrackGitCost(workflowID string, operations int) {
	ct.mu.Lock()
	defer ct.mu.Unlock()

	entry := &CostEntry{
		ID:         fmt.Sprintf("git-%d", len(ct.entries)),
		Type:       "git",
		WorkflowID: workflowID,
		Amount:     0,
		Timestamp:  time.Now(),
		Metadata: map[string]interface{}{
			"operations": operations,
		},
	}

	ct.entries = append(ct.entries, entry)
}

// TrackComputeCost tracks compute resource costs (duration in milliseconds)
func (ct *CostTracker) TrackComputeCost(workflowID, taskID string, durationMs float64) {
	// Convert milliseconds to hours
	durationHours := durationMs / (1000.0 * 3600.0)
	cost := durationHours * ct.rates["compute_hour"]
	ct.mu.Lock()
	defer ct.mu.Unlock()

	entry := &CostEntry{
		ID:         fmt.Sprintf("compute-%d", len(ct.entries)),
		Type:       "compute",
		WorkflowID: workflowID,
		TaskID:     taskID,
		Amount:     cost,
		Timestamp:  time.Now(),
		Metadata: map[string]interface{}{
			"duration_ms": durationMs,
		},
	}

	ct.entries = append(ct.entries, entry)
}

// GetTotalCost returns total cost for all workflows
func (ct *CostTracker) GetTotalCost() float64 {
	ct.mu.RLock()
	defer ct.mu.RUnlock()

	total := 0.0
	for _, entry := range ct.entries {
		total += entry.Amount
	}

	return total
}

// GetWorkflowCost returns total cost for a specific workflow
func (ct *CostTracker) GetWorkflowCost(workflowID string) float64 {
	ct.mu.RLock()
	defer ct.mu.RUnlock()

	total := 0.0
	for _, entry := range ct.entries {
		if entry.WorkflowID == workflowID {
			total += entry.Amount
		}
	}

	return total
}

// GetCostByType returns total cost by type
func (ct *CostTracker) GetCostByType(costType string) float64 {
	ct.mu.RLock()
	defer ct.mu.RUnlock()

	total := 0.0
	for _, entry := range ct.entries {
		if entry.Type == costType {
			total += entry.Amount
		}
	}

	return total
}

// GetAverageCostPerTask returns average cost per task
func (ct *CostTracker) GetAverageCostPerTask(workflowID string) float64 {
	ct.mu.RLock()
	defer ct.mu.RUnlock()

	total := 0.0
	count := 0

	for _, entry := range ct.entries {
		if entry.WorkflowID == workflowID {
			total += entry.Amount
			count++
		}
	}

	if count == 0 {
		return 0
	}

	return total / float64(count)
}

// GetOptimizationSuggestions returns cost optimization recommendations
func (ct *CostTracker) GetOptimizationSuggestions(workflowID string) []string {
	suggestions := make([]string, 0)

	ct.mu.RLock()
	defer ct.mu.RUnlock()

	llmCost := 0.0
	computeCost := 0.0

	for _, entry := range ct.entries {
		if entry.WorkflowID == workflowID {
			if entry.Type == "llm" {
				llmCost += entry.Amount
			} else if entry.Type == "compute" {
				computeCost += entry.Amount
			}
		}
	}

	if llmCost > computeCost*2 {
		suggestions = append(suggestions, "Consider caching LLM results to reduce API calls")
	}

	if computeCost > llmCost*2 {
		suggestions = append(suggestions, "Consider parallelizing compute tasks")
	}

	return suggestions
}

// GetEntries returns all cost entries
func (ct *CostTracker) GetEntries() []*CostEntry {
	ct.mu.RLock()
	defer ct.mu.RUnlock()

	result := make([]*CostEntry, len(ct.entries))
	copy(result, ct.entries)

	return result
}

// GetEntriesForWorkflow returns cost entries for a workflow
func (ct *CostTracker) GetEntriesForWorkflow(workflowID string) []*CostEntry {
	ct.mu.RLock()
	defer ct.mu.RUnlock()

	result := make([]*CostEntry, 0)
	for _, entry := range ct.entries {
		if entry.WorkflowID == workflowID {
			result = append(result, entry)
		}
	}

	return result
}

// SetRate sets the cost rate for a type
func (ct *CostTracker) SetRate(costType string, rate float64) {
	ct.mu.Lock()
	defer ct.mu.Unlock()

	ct.rates[costType] = rate
}

// GetRate gets the cost rate for a type
func (ct *CostTracker) GetRate(costType string) float64 {
	ct.mu.RLock()
	defer ct.mu.RUnlock()

	return ct.rates[costType]
}

// Clear clears all cost entries
func (ct *CostTracker) Clear() {
	ct.mu.Lock()
	defer ct.mu.Unlock()

	ct.entries = make([]*CostEntry, 0)
}
