package handlers

import (
	"github.com/breakpilot/ai-compliance-sdk/internal/iace"
	"github.com/google/uuid"
)

// componentReviewDecision captures an expert's manual review of an auto-detected
// component (presence move, CE marking, safety relevance) so a force re-seed can
// restore it instead of wiping it. Keyed by normalised component name — the
// deterministic narrative parser re-derives the same names.
type componentReviewDecision struct {
	presence       string
	ceMarked       bool
	safetyRelevant bool
}

// resolvePresence returns the presence_status for a freshly parsed component:
// the expert's prior decision wins; otherwise the engine's negation verdict
// (negated → nicht_vorhanden, else vorhanden).
func resolvePresence(dec componentReviewDecision, hasDecision, negated bool) string {
	if hasDecision && dec.presence != "" {
		return dec.presence
	}
	if negated {
		return iace.PresenceAbsent
	}
	return iace.PresencePresent
}

// pickComponentForPattern links a matched hazard pattern to the project
// component that most plausibly causes it.
//
// matchedTags are the component/energy tags that actually made the pattern fire
// (RequiredComponentTags + RequiredEnergyTags satisfied by the machine). The
// project component whose library tags overlap them best is treated as the
// cause. Falls back to zone-name overlap, then to the default (first) component.
//
// Without this, every hazard defaulted to the first component, so the knowledge
// graph drew all "erzeugt" edges from a single node.
func pickComponentForPattern(
	matchedTags []string,
	zoneDE string,
	parseComps []iace.ComponentMatch,
	compByName map[string]uuid.UUID,
	defaultCompID uuid.UUID,
) uuid.UUID {
	if len(matchedTags) > 0 {
		want := make(map[string]bool, len(matchedTags))
		for _, t := range matchedTags {
			want[t] = true
		}
		bestScore := 0
		bestID := uuid.Nil
		for _, c := range parseComps {
			id, ok := compByName[iace.NormalizeDEPublic(c.NameDE)]
			if !ok {
				continue
			}
			score := 0
			for _, t := range c.Tags {
				if want[t] {
					score++
				}
			}
			if score > bestScore {
				bestScore = score
				bestID = id
			}
		}
		if bestScore > 0 {
			return bestID
		}
	}

	if zoneDE != "" {
		zoneNorm := iace.NormalizeDEPublic(zoneDE)
		for cName, cID := range compByName {
			if containsSubstring(zoneNorm, cName) || containsSubstring(cName, zoneNorm) {
				return cID
			}
		}
	}

	return defaultCompID
}
