package iace

import "sort"

// Project-wide risk view, computed on read from each hazard's category / scenario
// / lifecycle using the SAME confidence-aware model as the benchmark
// (EstimateSeverity/Frequency/ProbabilityW/AvoidabilityP/RiskRange). Nothing is
// persisted — the risk is always derived from the hazard, so it can never go
// stale against the model (unlike the hand-defaulted iace_hazards risk columns).
// The matrix axis is Severity × Probability(W) — the classic risk matrix — since
// those are the two parameters an assessor reads off the grid.

// HazardRisk is the full confidence-aware risk estimate for one hazard.
type HazardRisk struct {
	Severity    int    `json:"severity"`
	Frequency   int    `json:"frequency"`
	Probability int    `json:"probability"` // W (occurrence)
	Avoidance   int    `json:"avoidance"`   // P
	RiskPoint   int    `json:"risk_point"`
	RiskLow     int    `json:"risk_low"`
	RiskHigh    int    `json:"risk_high"`
	Level       string `json:"level"`       // band of the point
	LevelRange  string `json:"level_range"` // e.g. "mittel–hoch"
	Confidence  string `json:"confidence"`  // hoch / mittel / niedrig
}

// EstimateHazardRisk derives the confidence-aware risk estimate for a hazard from
// its hazard category, scenario text and lifecycle phases. Single source of truth
// reused by the risk matrix endpoint.
func EstimateHazardRisk(cats []string, scenario string, lifecyclePhases []string) HazardRisk {
	s := EstimateSeverity(cats, scenario, 0)
	f := EstimateFrequency(lifecyclePhases)
	w := EstimateProbabilityW(cats, scenario)
	p := EstimateAvoidabilityP(cats, scenario)
	low, point, high := EstimateRiskRange(s, f, w, p)
	level, levelRange := RiskLevelRange(low, point, high)
	return HazardRisk{
		Severity: s, Frequency: f, Probability: w, Avoidance: p,
		RiskPoint: point, RiskLow: low, RiskHigh: high,
		Level: level, LevelRange: levelRange,
		Confidence: EstimateConfidence(cats, scenario),
	}
}

// HazardRiskDetail is one hazard plus its risk estimate (for the per-hazard list).
type HazardRiskDetail struct {
	HazardID string `json:"hazard_id"`
	Name     string `json:"name"`
	Category string `json:"category"`
	Zone     string `json:"zone"`
	HazardRisk
}

// RiskMatrixCell is one Severity×Probability bucket of the 5×5 grid.
type RiskMatrixCell struct {
	Severity      int      `json:"severity"`
	Probability   int      `json:"probability"`
	Count         int      `json:"count"`
	DominantLevel string   `json:"dominant_level"`
	HazardIDs     []string `json:"hazard_ids"`
}

// RiskMatrix is the project risk view: per-hazard detail + the aggregated grid.
type RiskMatrix struct {
	Hazards           []HazardRiskDetail `json:"hazards"`
	Matrix            []RiskMatrixCell   `json:"matrix"` // only non-empty cells
	LevelCounts       map[string]int     `json:"level_counts"`
	Total             int                `json:"total"`
	HighConfidencePct float64            `json:"high_confidence_pct"`
}

// bandRank orders risk levels so a cell's "dominant" (worst) level can be picked.
var bandRank = map[string]int{
	"vernachlaessigbar": 0, "gering": 1, "mittel": 2, "hoch": 3, "kritisch": 4,
}

// BuildRiskMatrix computes the confidence-aware risk for every hazard and
// aggregates them into a Severity×Probability grid.
func BuildRiskMatrix(hazards []Hazard) RiskMatrix {
	out := RiskMatrix{
		LevelCounts: map[string]int{},
		Total:       len(hazards),
	}
	type key struct{ s, w int }
	cells := map[key]*RiskMatrixCell{}
	hiConf := 0

	for _, h := range hazards {
		scenario := h.Scenario
		if scenario == "" {
			scenario = h.Name
		}
		risk := EstimateHazardRisk([]string{h.Category}, scenario, splitLifecyclePhases(h.LifecyclePhase))
		out.Hazards = append(out.Hazards, HazardRiskDetail{
			HazardID: h.ID.String(), Name: h.Name, Category: h.Category,
			Zone: h.HazardousZone, HazardRisk: risk,
		})
		out.LevelCounts[risk.Level]++
		if risk.Confidence == "hoch" {
			hiConf++
		}
		k := key{risk.Severity, risk.Probability}
		c := cells[k]
		if c == nil {
			c = &RiskMatrixCell{Severity: risk.Severity, Probability: risk.Probability, DominantLevel: risk.Level}
			cells[k] = c
		}
		c.Count++
		c.HazardIDs = append(c.HazardIDs, h.ID.String())
		if bandRank[risk.Level] > bandRank[c.DominantLevel] {
			c.DominantLevel = risk.Level
		}
	}

	for _, c := range cells {
		out.Matrix = append(out.Matrix, *c)
	}
	// Deterministic order: by severity desc, then probability desc.
	sort.Slice(out.Matrix, func(i, j int) bool {
		if out.Matrix[i].Severity != out.Matrix[j].Severity {
			return out.Matrix[i].Severity > out.Matrix[j].Severity
		}
		return out.Matrix[i].Probability > out.Matrix[j].Probability
	})
	if len(hazards) > 0 {
		out.HighConfidencePct = pct(hiConf, len(hazards))
	}
	return out
}
