package gci

import "math"

// ISOGapAnalysis represents the complete ISO 27001 gap analysis
type ISOGapAnalysis struct {
	TenantID         string                `json:"tenant_id"`
	TotalControls    int                   `json:"total_controls"`
	CoveredFull      int                   `json:"covered_full"`
	CoveredPartial   int                   `json:"covered_partial"`
	NotCovered       int                   `json:"not_covered"`
	CoveragePercent  float64               `json:"coverage_percent"`
	CategorySummaries []ISOCategorySummary  `json:"category_summaries"`
	ControlDetails   []ISOControlDetail    `json:"control_details"`
	Gaps             []ISOGap              `json:"gaps"`
}

// ISOControlDetail shows coverage status for a single control
type ISOControlDetail struct {
	Control       ISOControl `json:"control"`
	CoverageLevel string     `json:"coverage_level"` // full, partial, none
	CoveredBy     []string   `json:"covered_by"`     // module IDs
	Score         float64    `json:"score"`           // 0-100
}

// ISOGap represents an identified gap in ISO coverage
type ISOGap struct {
	ControlID   string `json:"control_id"`
	ControlName string `json:"control_name"`
	Category    string `json:"category"`
	Priority    string `json:"priority"` // high, medium, low
	Recommendation string `json:"recommendation"`
}

// CalculateISOGapAnalysis performs the ISO 27001 gap analysis
func CalculateISOGapAnalysis(tenantID string) *ISOGapAnalysis {
	modules := MockModuleData(tenantID)
	moduleMap := map[string]ModuleScore{}
	for _, m := range modules {
		moduleMap[m.ModuleID] = m
	}

	// Build reverse mapping: control -> modules covering it
	controlCoverage := map[string][]string{}
	controlCoverageLevel := map[string]string{}
	for _, mapping := range DefaultISOModuleMappings {
		for _, controlID := range mapping.ISOControls {
			controlCoverage[controlID] = append(controlCoverage[controlID], mapping.ModuleID)
			// Use the highest coverage level
			existingLevel := controlCoverageLevel[controlID]
			if mapping.CoverageLevel == "full" || existingLevel == "" {
				controlCoverageLevel[controlID] = mapping.CoverageLevel
			}
		}
	}

	// Analyze each control
	details := []ISOControlDetail{}
	gaps := []ISOGap{}
	coveredFull := 0
	coveredPartial := 0
	notCovered := 0

	categoryCounts := map[string]*ISOCategorySummary{
		"A.5": {CategoryID: "A.5", CategoryName: "Organisatorische Massnahmen"},
		"A.6": {CategoryID: "A.6", CategoryName: "Personelle Massnahmen"},
		"A.7": {CategoryID: "A.7", CategoryName: "Physische Massnahmen"},
		"A.8": {CategoryID: "A.8", CategoryName: "Technologische Massnahmen"},
	}

	for _, control := range ISOControls {
		coveredBy := controlCoverage[control.ID]
		level := controlCoverageLevel[control.ID]

		if len(coveredBy) == 0 {
			level = "none"
		}

		// Calculate score based on module completion
		score := 0.0
		if len(coveredBy) > 0 {
			scoreSum := 0.0
			count := 0
			for _, modID := range coveredBy {
				if m, ok := moduleMap[modID]; ok && m.Assigned > 0 {
					scoreSum += float64(m.Completed) / float64(m.Assigned) * 100
					count++
				}
			}
			if count > 0 {
				score = scoreSum / float64(count)
			}
			// Adjust for coverage level
			if level == "partial" {
				score *= 0.7 // partial coverage reduces effective score
			}
		}

		detail := ISOControlDetail{
			Control:       control,
			CoverageLevel: level,
			CoveredBy:     coveredBy,
			Score:         math.Round(score*10) / 10,
		}
		details = append(details, detail)

		// Count by category
		cat := categoryCounts[control.CategoryID]
		if cat != nil {
			cat.TotalControls++
			switch level {
			case "full":
				coveredFull++
				cat.CoveredFull++
			case "partial":
				coveredPartial++
				cat.CoveredPartial++
			default:
				notCovered++
				cat.NotCovered++
				// Generate gap recommendation
				gap := ISOGap{
					ControlID:   control.ID,
					ControlName: control.Name,
					Category:    control.Category,
					Priority:    determineGapPriority(control),
					Recommendation: generateGapRecommendation(control),
				}
				gaps = append(gaps, gap)
			}
		}
	}

	totalControls := len(ISOControls)
	coveragePercent := 0.0
	if totalControls > 0 {
		coveragePercent = math.Round(float64(coveredFull+coveredPartial)/float64(totalControls)*100*10) / 10
	}

	summaries := []ISOCategorySummary{}
	for _, catID := range []string{"A.5", "A.6", "A.7", "A.8"} {
		if cat, ok := categoryCounts[catID]; ok {
			summaries = append(summaries, *cat)
		}
	}

	return &ISOGapAnalysis{
		TenantID:          tenantID,
		TotalControls:     totalControls,
		CoveredFull:       coveredFull,
		CoveredPartial:    coveredPartial,
		NotCovered:        notCovered,
		CoveragePercent:   coveragePercent,
		CategorySummaries: summaries,
		ControlDetails:    details,
		Gaps:              gaps,
	}
}

func determineGapPriority(control ISOControl) string {
	// High priority for access, incident, and data protection controls
	highPriority := map[string]bool{
		"A.5.15": true, "A.5.17": true, "A.5.24": true, "A.5.26": true,
		"A.5.34": true, "A.8.2": true, "A.8.5": true, "A.8.7": true,
		"A.8.10": true, "A.8.20": true,
	}
	if highPriority[control.ID] {
		return "high"
	}
	// Medium for organizational and people controls
	if control.CategoryID == "A.5" || control.CategoryID == "A.6" {
		return "medium"
	}
	return "low"
}

func generateGapRecommendation(control ISOControl) string {
	recommendations := map[string]string{
		"organizational": "Erstellen Sie eine Richtlinie und weisen Sie Verantwortlichkeiten zu fuer: " + control.Name,
		"people":         "Implementieren Sie Schulungen und Prozesse fuer: " + control.Name,
		"physical":       "Definieren Sie physische Sicherheitsmassnahmen fuer: " + control.Name,
		"technological":  "Implementieren Sie technische Kontrollen fuer: " + control.Name,
	}
	if rec, ok := recommendations[control.Category]; ok {
		return rec
	}
	return "Massnahmen implementieren fuer: " + control.Name
}
