package core

import (
	"container/heap"
	"gitea.deepblack.cloud/chorus/bubble/models"
	"gitea.deepblack.cloud/chorus/bubble/storage"
)

// --- Priority Queue for Scoring ---

// An Item is something we manage in a priority queue.
type scoredItem struct {
	summary  models.DecisionRecordSummary
	priority float64 // The priority of the item in the queue.
	index    int     // The index of the item in the heap.
}

// A PriorityQueue implements heap.Interface and holds Items.
type PriorityQueue []*scoredItem

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	// We want Pop to give us the highest, not lowest, priority so we use greater than here.
	return pq[i].priority > pq[j].priority
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
	pq[i].index = i
	pq[j].index = j
}

func (pq *PriorityQueue) Push(x interface{}) {
	n := len(*pq)
	item := x.(*scoredItem)
	item.index = n
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	old[n-1] = nil  // avoid memory leak
	item.index = -1 // for safety
	*pq = old[0 : n-1]
	return item
}

// --- Core Logic ---

// WalkBack performs a scored, role-aware walk of the provenance graph.
func WalkBack(store storage.Storage, startID, query, role string, maxHops, topK int) ([]models.DecisionRecordSummary, error) {
	visited := make(map[string]bool)
	pq := make(PriorityQueue, 0)
	heap.Init(&pq)

	queue := []struct {
		id    string
		depth int
	}{{startID, 0}}
	visited[startID] = true

	// Placeholder for query embedding
	// queryVec := embed(query)

	for len(queue) > 0 {
		current := queue[0]
		queue = queue[1:]

		if current.depth > maxHops {
			continue
		}

		// Fetch metadata for the current node
		meta, err := store.GetDecisionMetadata(current.id)
		if err != nil {
			// Log or handle error, maybe continue
			continue
		}
		if meta == nil {
			continue
		}

		// Role-based filtering
		if exposure, ok := meta.RoleExposure[role]; !ok || !exposure {
			// If role not in map or is false, skip
			// (Unless it's a global admin role, etc. - logic can be added here)
		}

		// --- Scoring ---
		// simScore := cosineSimilarity(queryVec, embed(meta.Statement))
		simScore := 0.5 // Placeholder value
		distScore := float64(maxHops-current.depth) / float64(maxHops)
		constraintPenalty := 0.0 // Placeholder

		totalScore := (0.6*simScore) + (0.3*distScore) + constraintPenalty
		meta.Score = totalScore

		heap.Push(&pq, &scoredItem{summary: *meta, priority: totalScore})

		// --- Traverse Ancestors ---
		ancestors, err := store.GetAncestors(current.id)
		if err != nil {
			// Log or handle error
			continue
		}

		for _, ancID := range ancestors {
			if !visited[ancID] {
				visited[ancID] = true
				queue = append(queue, struct {
					id    string
					depth int
				}{ancID, current.depth + 1})
			}
		}
	}

	// Extract top K results from the priority queue
	var results []models.DecisionRecordSummary
	for i := 0; i < topK && pq.Len() > 0; i++ {
		item := heap.Pop(&pq).(*scoredItem)
		results = append(results, item.summary)
	}

	return results, nil
}