package handlers import ( "net/http" "github.com/breakpilot/ai-compliance-sdk/internal/iace" "github.com/gin-gonic/gin" "github.com/google/uuid" ) // GetHazardBlocks handles GET /projects/:id/hazard-blocks // Returns hazards grouped into parent-child blocks based on shared category, // component, and zone. The parent hazard in each block has the highest risk. // Children covered by the parent's measures are flagged accordingly. func (h *IACEHandler) GetHazardBlocks(c *gin.Context) { projectID, err := uuid.Parse(c.Param("id")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"}) return } ctx := c.Request.Context() hazards, err := h.store.ListHazards(ctx, projectID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load hazards"}) return } assessmentMap, _ := h.store.GetLatestAssessmentsByProject(ctx, projectID) var assessments []iace.RiskAssessment for _, a := range assessmentMap { assessments = append(assessments, a) } mitigations, _ := h.store.ListMitigationsByProject(ctx, projectID) blocks := iace.ComputeHazardBlocks(hazards, assessments, mitigations) // Compute summary stats totalBlocks := len(blocks) parentOnly := 0 coveredChildren := 0 uncoveredChildren := 0 for _, b := range blocks { if len(b.Children) == 0 { parentOnly++ } else if b.ChildrenCoveredByParent { coveredChildren += len(b.Children) } else { uncoveredChildren += len(b.Children) } } c.JSON(http.StatusOK, gin.H{ "blocks": blocks, "summary": gin.H{ "total_blocks": totalBlocks, "parent_only_blocks": parentOnly, "blocks_with_children": totalBlocks - parentOnly, "total_hazards": len(hazards), "covered_children": coveredChildren, "uncovered_children": uncoveredChildren, "assessments_needed": totalBlocks - parentOnly + uncoveredChildren + parentOnly, "assessments_saved": coveredChildren, }, }) }