package schema

import "fmt"

// ValidateDomainGraph enforces the hierarchy emitted by UA's domain-analyzer
// after the standard graph validator has normalized the graph envelope.
func ValidateDomainGraph(graph KnowledgeGraph) error {
	if len(graph.Layers) != 0 || len(graph.Tour) != 0 {
		return fmt.Errorf("layers and tour must be empty")
	}
	types := make(map[string]string, len(graph.Nodes))
	for _, node := range graph.Nodes {
		switch node.Type {
		case "domain", "flow", "step":
		default:
			return fmt.Errorf("node %q has non-domain type %q", node.ID, node.Type)
		}
		if _, exists := types[node.ID]; exists {
			return fmt.Errorf("duplicate node id %q", node.ID)
		}
		types[node.ID] = node.Type
	}
	parents := make(map[string]int, len(graph.Nodes))
	for _, edge := range graph.Edges {
		if edge.Source == edge.Target {
			return fmt.Errorf("self-referencing edge %q", edge.Source)
		}
		sourceType, targetType := types[edge.Source], types[edge.Target]
		switch edge.Type {
		case "contains_flow":
			if sourceType != "domain" || targetType != "flow" {
				return fmt.Errorf("contains_flow must connect domain to flow")
			}
			parents[edge.Target]++
		case "flow_step":
			if sourceType != "flow" || targetType != "step" {
				return fmt.Errorf("flow_step must connect flow to step")
			}
			parents[edge.Target]++
		case "cross_domain":
			if sourceType != "domain" || targetType != "domain" {
				return fmt.Errorf("cross_domain must connect domains")
			}
		default:
			return fmt.Errorf("edge has non-domain type %q", edge.Type)
		}
	}
	for _, node := range graph.Nodes {
		if node.Type != "domain" && parents[node.ID] == 0 {
			return fmt.Errorf("%s %q has no parent", node.Type, node.ID)
		}
		if node.Type != "domain" && parents[node.ID] > 1 {
			return fmt.Errorf("%s %q has multiple parents", node.Type, node.ID)
		}
	}
	return nil
}
