package gci

import "math"

// NIS2Score represents the NIS2-specific compliance score
type NIS2Score struct {
	TenantID       string           `json:"tenant_id"`
	OverallScore   float64          `json:"overall_score"`
	MaturityLevel  string           `json:"maturity_level"`
	MaturityLabel  string           `json:"maturity_label"`
	AreaScores     []NIS2AreaScore  `json:"area_scores"`
	RoleCompliance []NIS2RoleScore  `json:"role_compliance"`
}

// NIS2AreaScore represents a NIS2 compliance area
type NIS2AreaScore struct {
	AreaID    string  `json:"area_id"`
	AreaName  string  `json:"area_name"`
	Score     float64 `json:"score"`
	Weight    float64 `json:"weight"`
	ModuleIDs []string `json:"module_ids"`
}

// NIS2RoleScore represents completion per NIS2 role
type NIS2RoleScore struct {
	RoleID          string  `json:"role_id"`
	RoleName        string  `json:"role_name"`
	AssignedUsers   int     `json:"assigned_users"`
	CompletionRate  float64 `json:"completion_rate"`
	MandatoryTotal  int     `json:"mandatory_total"`
	MandatoryDone   int     `json:"mandatory_done"`
}

// NIS2 scoring areas with weights
// NIS2Score = 25% Management + 25% Incident + 30% IT Security + 20% Supply Chain
var nis2Areas = []struct {
	ID        string
	Name      string
	Weight    float64
	ModuleIDs []string
}{
	{
		ID: "management", Name: "Management & Governance", Weight: 0.25,
		ModuleIDs: []string{"nis2-management", "dsgvo-grundlagen", "iso-isms"},
	},
	{
		ID: "incident", Name: "Vorfallsbehandlung", Weight: 0.25,
		ModuleIDs: []string{"nis2-incident-response"},
	},
	{
		ID: "it_security", Name: "IT-Sicherheit", Weight: 0.30,
		ModuleIDs: []string{"nis2-risikomanagement", "iso-zugangssteuerung", "iso-kryptografie"},
	},
	{
		ID: "supply_chain", Name: "Lieferkettensicherheit", Weight: 0.20,
		ModuleIDs: []string{"nis2-supply-chain", "dsgvo-auftragsverarbeitung"},
	},
}

// CalculateNIS2Score computes the NIS2-specific compliance score
func CalculateNIS2Score(tenantID string) *NIS2Score {
	modules := MockModuleData(tenantID)
	moduleMap := map[string]ModuleScore{}
	for _, m := range modules {
		moduleMap[m.ModuleID] = m
	}

	areaScores := []NIS2AreaScore{}
	totalWeighted := 0.0

	for _, area := range nis2Areas {
		areaScore := NIS2AreaScore{
			AreaID:    area.ID,
			AreaName:  area.Name,
			Weight:    area.Weight,
			ModuleIDs: area.ModuleIDs,
		}

		scoreSum := 0.0
		count := 0
		for _, modID := range area.ModuleIDs {
			if m, ok := moduleMap[modID]; ok {
				if m.Assigned > 0 {
					scoreSum += float64(m.Completed) / float64(m.Assigned) * 100
				}
				count++
			}
		}
		if count > 0 {
			areaScore.Score = math.Round(scoreSum/float64(count)*10) / 10
		}
		totalWeighted += areaScore.Score * areaScore.Weight
		areaScores = append(areaScores, areaScore)
	}

	overallScore := math.Round(totalWeighted*10) / 10

	// Calculate role compliance
	roleAssignments := MockNIS2RoleAssignments(tenantID)
	roleScores := calculateNIS2RoleScores(roleAssignments, moduleMap)

	return &NIS2Score{
		TenantID:       tenantID,
		OverallScore:   overallScore,
		MaturityLevel:  determineMaturityLevel(overallScore),
		MaturityLabel:  MaturityLabels[determineMaturityLevel(overallScore)],
		AreaScores:     areaScores,
		RoleCompliance: roleScores,
	}
}

func calculateNIS2RoleScores(assignments []NIS2RoleAssignment, moduleMap map[string]ModuleScore) []NIS2RoleScore {
	// Count users per role
	roleCounts := map[string]int{}
	for _, a := range assignments {
		roleCounts[a.RoleID]++
	}

	scores := []NIS2RoleScore{}
	for roleID, role := range NIS2Roles {
		rs := NIS2RoleScore{
			RoleID:         roleID,
			RoleName:       role.Name,
			AssignedUsers:  roleCounts[roleID],
			MandatoryTotal: len(role.MandatoryModules),
		}

		completionSum := 0.0
		for _, modID := range role.MandatoryModules {
			if m, ok := moduleMap[modID]; ok {
				if m.Assigned > 0 {
					rate := float64(m.Completed) / float64(m.Assigned)
					completionSum += rate
					if rate >= 0.8 { // 80%+ = considered done
						rs.MandatoryDone++
					}
				}
			}
		}
		if rs.MandatoryTotal > 0 {
			rs.CompletionRate = math.Round(completionSum/float64(rs.MandatoryTotal)*100*10) / 10
		}
		scores = append(scores, rs)
	}

	return scores
}
