#!/usr/bin/env python3
"""
VigileGuard Phase 2: Enhanced Reporting System
HTML reports, compliance mapping, and trend tracking
"""

import json
import os
from datetime import datetime, timedelta
from typing import List, Dict, Any, Optional
from pathlib import Path
import tempfile
import hashlib

# Re-define required classes to avoid circular imports
from enum import Enum
from dataclasses import dataclass, asdict

class SeverityLevel(Enum):
    """Security finding severity levels"""
    CRITICAL = "CRITICAL"
    HIGH = "HIGH"
    MEDIUM = "MEDIUM"
    LOW = "LOW"
    INFO = "INFO"

@dataclass
class Finding:
    """Represents a security finding"""
    category: str
    severity: SeverityLevel
    title: str
    description: str
    recommendation: str
    details: Optional[Dict[str, Any]] = None  

    def to_dict(self) -> Dict[str, Any]:
        """Convert finding to dictionary"""
        result = asdict(self)
        result["severity"] = self.severity.value
        return result


class HTMLReporter:
    """Generate HTML security reports"""
    
    def __init__(self, findings: List[Finding], scan_info: Dict[str, Any]):
        self.findings = findings
        self.scan_info = scan_info
    
    def generate_report(self, output_path: str) -> str:
        """Generate comprehensive HTML report"""
        html_content = self._create_html_template()
        
        with open(output_path, 'w') as f:
            f.write(html_content)
        
        return output_path
    
    def _create_html_template(self) -> str:
        """Create HTML report template"""
        summary = self._generate_summary()
        findings_html = self._generate_findings_html()
        charts_data = self._generate_charts_data()
        
        html_template = f"""
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>VigileGuard Security Report</title>
    <style>
        {self._get_css_styles()}
    </style>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
    <div class="container">
        <header class="header">
            <h1>🛡️ VigileGuard Security Report</h1>
            <div class="scan-info">
                <p><strong>Scan Date:</strong> {self.scan_info.get('timestamp', 'Unknown')}</p>
                <p><strong>Hostname:</strong> {self.scan_info.get('hostname', 'Unknown')}</p>
                <p><strong>Version:</strong> {self.scan_info.get('version', '1.0.0')}</p>
            </div>
        </header>
        
        <section class="summary">
            {summary}
        </section>
        
        <section class="charts">
            <div class="chart-container">
                <canvas id="severityChart"></canvas>
            </div>
            <div class="chart-container">
                <canvas id="categoryChart"></canvas>
            </div>
        </section>
        
        <section class="findings">
            <h2>Detailed Findings</h2>
            {findings_html}
        </section>
        
        <footer class="footer">
            <p>Generated by VigileGuard v{self.scan_info.get('version', '1.0.0')} | 
            <a href="https://github.com/navinnm/VigileGuard">GitHub Repository</a></p>
        </footer>
    </div>
    
    <script>
        {self._get_javascript_code(charts_data)}
    </script>
</body>
</html>
        """
        return html_template
    
    def _generate_summary(self) -> str:
        """Generate summary section"""
        severity_counts = {}
        category_counts = {}
        
        for finding in self.findings:
            # Count by severity
            severity = finding.severity.value
            severity_counts[severity] = severity_counts.get(severity, 0) + 1
            
            # Count by category
            category = finding.category
            category_counts[category] = category_counts.get(category, 0) + 1
        
        total_findings = len(self.findings)
        critical_high = severity_counts.get('CRITICAL', 0) + severity_counts.get('HIGH', 0)
        
        # Determine overall risk level
        if critical_high > 5:
            risk_level = "HIGH RISK"
            risk_class = "risk-high"
        elif critical_high > 0:
            risk_level = "MEDIUM RISK"
            risk_class = "risk-medium"
        else:
            risk_level = "LOW RISK"
            risk_class = "risk-low"
        
        summary_html = f"""
        <div class="summary-cards">
            <div class="summary-card total">
                <h3>Total Findings</h3>
                <div class="number">{total_findings}</div>
            </div>
            <div class="summary-card {risk_class}">
                <h3>Risk Level</h3>
                <div class="risk-level">{risk_level}</div>
            </div>
            <div class="summary-card critical">
                <h3>Critical/High</h3>
                <div class="number">{critical_high}</div>
            </div>
        </div>
        
        <div class="severity-breakdown">
            <h3>Severity Breakdown</h3>
            <div class="severity-grid">
        """
        
        severity_colors = {
            'CRITICAL': '#dc3545',
            'HIGH': '#fd7e14', 
            'MEDIUM': '#ffc107',
            'LOW': '#20c997',
            'INFO': '#6c757d'
        }
        
        for severity, color in severity_colors.items():
            count = severity_counts.get(severity, 0)
            summary_html += f"""
                <div class="severity-item">
                    <span class="severity-badge" style="background-color: {color};">{severity}</span>
                    <span class="severity-count">{count}</span>
                </div>
            """
        
        summary_html += """
            </div>
        </div>
        """
        
        return summary_html
    
    def _generate_findings_html(self) -> str:
        """Generate findings section HTML"""
        findings_html = ""
        
        # Group findings by severity
        findings_by_severity = {}
        for finding in self.findings:
            severity = finding.severity.value
            if severity not in findings_by_severity:
                findings_by_severity[severity] = []
            findings_by_severity[severity].append(finding)
        
        # Order by severity
        severity_order = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'INFO']
        
        for severity in severity_order:
            if severity in findings_by_severity:
                findings_html += f"""
                <div class="severity-section">
                    <h3 class="severity-header severity-{severity.lower()}">{severity} Issues ({len(findings_by_severity[severity])})</h3>
                """
                
                for finding in findings_by_severity[severity]:
                    findings_html += self._generate_finding_card(finding)
                
                findings_html += "</div>"
        
        return findings_html
    
    def _generate_finding_card(self, finding: Finding) -> str:
        """Generate individual finding card"""
        details_html = ""
        if finding.details:
            details_html = f"""
            <div class="finding-details">
                <strong>Details:</strong>
                <pre>{json.dumps(finding.details, indent=2)}</pre>
            </div>
            """
        
        severity_class = finding.severity.value.lower()
        
        return f"""
        <div class="finding-card severity-{severity_class}">
            <div class="finding-header">
                <h4>{finding.title}</h4>
                <span class="severity-badge severity-{severity_class}">{finding.severity.value}</span>
            </div>
            <div class="finding-category">Category: {finding.category}</div>
            <div class="finding-description">{finding.description}</div>
            <div class="finding-recommendation">
                <strong>Recommendation:</strong> {finding.recommendation}
            </div>
            {details_html}
        </div>
        """
    
    def _generate_charts_data(self) -> Dict[str, Any]:
        """Generate data for charts"""
        severity_counts = {}
        category_counts = {}
        
        for finding in self.findings:
            # Count by severity
            severity = finding.severity.value
            severity_counts[severity] = severity_counts.get(severity, 0) + 1
            
            # Count by category
            category = finding.category
            category_counts[category] = category_counts.get(category, 0) + 1
        
        return {
            'severity': severity_counts,
            'category': category_counts
        }
    
    def _get_css_styles(self) -> str:
        """Get CSS styles for the report"""
        return """
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            line-height: 1.6;
            color: #333;
            background-color: #f8f9fa;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }
        
        .header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 30px;
            border-radius: 10px;
            margin-bottom: 30px;
            text-align: center;
        }
        
        .header h1 {
            font-size: 2.5rem;
            margin-bottom: 10px;
        }
        
        .scan-info {
            display: flex;
            justify-content: center;
            gap: 30px;
            flex-wrap: wrap;
        }
        
        .summary {
            margin-bottom: 30px;
        }
        
        .summary-cards {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin-bottom: 30px;
        }
        
        .summary-card {
            background: white;
            padding: 20px;
            border-radius: 10px;
            text-align: center;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        .summary-card h3 {
            color: #666;
            margin-bottom: 10px;
        }
        
        .summary-card .number {
            font-size: 2rem;
            font-weight: bold;
            color: #333;
        }
        
        .summary-card .risk-level {
            font-size: 1.5rem;
            font-weight: bold;
        }
        
        .risk-high .risk-level { color: #dc3545; }
        .risk-medium .risk-level { color: #fd7e14; }
        .risk-low .risk-level { color: #28a745; }
        
        .severity-breakdown {
            background: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        .severity-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 15px;
            margin-top: 15px;
        }
        
        .severity-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 10px;
            background: #f8f9fa;
            border-radius: 5px;
        }
        
        .severity-badge {
            color: white;
            padding: 4px 8px;
            border-radius: 4px;
            font-size: 0.8rem;
            font-weight: bold;
        }
        
        .severity-count {
            font-weight: bold;
            font-size: 1.2rem;
        }
        
        .charts {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
            gap: 30px;
            margin-bottom: 30px;
        }
        
        .chart-container {
            background: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        
        .findings {
            margin-bottom: 30px;
        }
        
        .findings h2 {
            margin-bottom: 20px;
            color: #333;
        }
        
        .severity-section {
            margin-bottom: 30px;
        }
        
        .severity-header {
            padding: 15px;
            border-radius: 10px 10px 0 0;
            color: white;
            font-size: 1.3rem;
        }
        
        .severity-critical { background-color: #dc3545; }
        .severity-high { background-color: #fd7e14; }
        .severity-medium { background-color: #ffc107; color: #333; }
        .severity-low { background-color: #28a745; }
        .severity-info { background-color: #6c757d; }
        
        .finding-card {
            background: white;
            border-left: 5px solid #ddd;
            padding: 20px;
            margin-bottom: 15px;
            border-radius: 0 10px 10px 0;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }
        
        .finding-card.severity-critical { border-left-color: #dc3545; }
        .finding-card.severity-high { border-left-color: #fd7e14; }
        .finding-card.severity-medium { border-left-color: #ffc107; }
        .finding-card.severity-low { border-left-color: #28a745; }
        .finding-card.severity-info { border-left-color: #6c757d; }
        
        .finding-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
        }
        
        .finding-header h4 {
            color: #333;
            margin: 0;
        }
        
        .finding-category {
            color: #666;
            font-size: 0.9rem;
            margin-bottom: 10px;
        }
        
        .finding-description {
            margin-bottom: 15px;
            line-height: 1.6;
        }
        
        .finding-recommendation {
            background: #f8f9fa;
            padding: 10px;
            border-radius: 5px;
            margin-bottom: 15px;
        }
        
        .finding-details {
            background: #f8f9fa;
            padding: 10px;
            border-radius: 5px;
        }
        
        .finding-details pre {
            font-size: 0.8rem;
            overflow-x: auto;
        }
        
        .footer {
            text-align: center;
            padding: 20px;
            color: #666;
            border-top: 1px solid #ddd;
        }
        
        .footer a {
            color: #667eea;
            text-decoration: none;
        }
        
        @media (max-width: 768px) {
            .scan-info {
                flex-direction: column;
                gap: 10px;
            }
            
            .charts {
                grid-template-columns: 1fr;
            }
            
            .finding-header {
                flex-direction: column;
                align-items: flex-start;
                gap: 10px;
            }
        }
        """
    
    def _get_javascript_code(self, charts_data: Dict[str, Any]) -> str:
        """Get JavaScript code for charts"""
        return f"""
        // Chart.js configuration
        const severityData = {json.dumps(charts_data['severity'])};
        const categoryData = {json.dumps(charts_data['category'])};
        
        // Severity Chart
        const severityCtx = document.getElementById('severityChart').getContext('2d');
        new Chart(severityCtx, {{
            type: 'doughnut',
            data: {{
                labels: Object.keys(severityData),
                datasets: [{{
                    data: Object.values(severityData),
                    backgroundColor: [
                        '#dc3545',  // CRITICAL
                        '#fd7e14',  // HIGH
                        '#ffc107',  // MEDIUM
                        '#28a745',  // LOW
                        '#6c757d'   // INFO
                    ]
                }}]
            }},
            options: {{
                responsive: true,
                plugins: {{
                    title: {{
                        display: true,
                        text: 'Findings by Severity'
                    }},
                    legend: {{
                        position: 'bottom'
                    }}
                }}
            }}
        }});
        
        // Category Chart
        const categoryCtx = document.getElementById('categoryChart').getContext('2d');
        new Chart(categoryCtx, {{
            type: 'bar',
            data: {{
                labels: Object.keys(categoryData),
                datasets: [{{
                    label: 'Findings',
                    data: Object.values(categoryData),
                    backgroundColor: 'rgba(102, 126, 234, 0.8)',
                    borderColor: 'rgba(102, 126, 234, 1)',
                    borderWidth: 1
                }}]
            }},
            options: {{
                responsive: true,
                plugins: {{
                    title: {{
                        display: true,
                        text: 'Findings by Category'
                    }}
                }},
                scales: {{
                    y: {{
                        beginAtZero: true,
                        ticks: {{
                            stepSize: 1
                        }}
                    }}
                }}
            }}
        }});
        """


class ComplianceMapper:
    """Map security findings to compliance frameworks"""
    
    def __init__(self):
        self.framework_mappings = {
            'PCI_DSS': {
                'description': 'Payment Card Industry Data Security Standard',
                'mappings': {
                    'File Permissions': ['2.2.4', '7.1.1'],
                    'User Accounts': ['7.1.2', '8.1.1', '8.2.3'],
                    'SSH': ['2.3', '8.2.1'],
                    'Web Server': ['2.2.3', '6.5.10'],
                    'Network Security': ['1.3.1', '2.2.2']
                }
            },
            'SOC_2': {
                'description': 'Service Organization Control 2',
                'mappings': {
                    'File Permissions': ['CC6.1', 'CC6.3'],
                    'User Accounts': ['CC6.1', 'CC6.2'],
                    'SSH': ['CC6.1', 'CC6.7'],
                    'Web Server': ['CC6.1', 'CC6.8'],
                    'Network Security': ['CC6.1', 'CC6.6']
                }
            },
            'NIST_CSF': {
                'description': 'NIST Cybersecurity Framework',
                'mappings': {
                    'File Permissions': ['PR.AC-1', 'PR.AC-4'],
                    'User Accounts': ['PR.AC-1', 'PR.AC-7'],
                    'SSH': ['PR.AC-3', 'PR.AC-7'],
                    'Web Server': ['PR.AC-3', 'PR.PT-3'],
                    'Network Security': ['PR.AC-3', 'PR.AC-5']
                }
            },
            'ISO_27001': {
                'description': 'ISO/IEC 27001:2013',
                'mappings': {
                    'File Permissions': ['A.9.1.1', 'A.9.2.3'],
                    'User Accounts': ['A.9.2.1', 'A.9.2.2'],
                    'SSH': ['A.9.4.2', 'A.13.1.1'],
                    'Web Server': ['A.13.1.1', 'A.14.1.3'],
                    'Network Security': ['A.13.1.1', 'A.13.1.3']
                }
            }
        }
    
    def generate_compliance_report(self, findings: List[Finding], frameworks: List[str] = None) -> Dict[str, Any]:
        """Generate compliance mapping report"""
        if frameworks is None:
            frameworks = list(self.framework_mappings.keys())
        
        compliance_report = {
            'frameworks': {},
            'coverage_summary': {},
            'recommendations': []
        }
        
        for framework in frameworks:
            if framework in self.framework_mappings:
                compliance_report['frameworks'][framework] = self._map_findings_to_framework(
                    findings, framework
                )
        
        compliance_report['coverage_summary'] = self._calculate_coverage_summary(findings, frameworks)
        compliance_report['recommendations'] = self._generate_compliance_recommendations(findings, frameworks)
        
        return compliance_report
    
    def _map_findings_to_framework(self, findings: List[Finding], framework: str) -> Dict[str, Any]:
        """Map findings to specific compliance framework"""
        framework_data = self.framework_mappings[framework]
        mapped_findings = {}
        
        for finding in findings:
            category = finding.category
            if category in framework_data['mappings']:
                controls = framework_data['mappings'][category]
                for control in controls:
                    if control not in mapped_findings:
                        mapped_findings[control] = []
                    mapped_findings[control].append({
                        'title': finding.title,
                        'severity': finding.severity.value,
                        'category': finding.category,
                        'description': finding.description
                    })
        
        return {
            'description': framework_data['description'],
            'mapped_controls': mapped_findings,
            'total_controls_affected': len(mapped_findings),
            'total_findings_mapped': sum(len(findings) for findings in mapped_findings.values())
        }
    
    def _calculate_coverage_summary(self, findings: List[Finding], frameworks: List[str]) -> Dict[str, Any]:
        """Calculate compliance coverage summary"""
        summary = {}
        
        for framework in frameworks:
            if framework in self.framework_mappings:
                framework_data = self.framework_mappings[framework]
                total_controls = sum(len(controls) for controls in framework_data['mappings'].values())
                
                mapped_findings = self._map_findings_to_framework(findings, framework)
                affected_controls = mapped_findings['total_controls_affected']
                
                coverage_percentage = (affected_controls / total_controls * 100) if total_controls > 0 else 0
                
                summary[framework] = {
                    'total_controls': total_controls,
                    'affected_controls': affected_controls,
                    'coverage_percentage': round(coverage_percentage, 2),
                    'compliance_level': self._determine_compliance_level(coverage_percentage)
                }
        
        return summary
    
    def _determine_compliance_level(self, coverage_percentage: float) -> str:
        """Determine compliance level based on coverage"""
        if coverage_percentage < 20:
            return "Good"
        elif coverage_percentage < 50:
            return "Needs Attention"
        else:
            return "Requires Immediate Action"
    
    def _generate_compliance_recommendations(self, findings: List[Finding], frameworks: List[str]) -> List[Dict[str, Any]]:
        """Generate compliance-specific recommendations"""
        recommendations = []
        
        # Group findings by severity
        critical_high_findings = [f for f in findings if f.severity in [SeverityLevel.CRITICAL, SeverityLevel.HIGH]]
        
        if critical_high_findings:
            recommendations.append({
                'priority': 'High',
                'title': 'Address Critical and High Severity Issues',
                'description': f'Found {len(critical_high_findings)} critical/high severity issues that impact compliance',
                'frameworks_affected': frameworks,
                'estimated_effort': 'High'
            })
        
        # Category-specific recommendations
        category_counts = {}
        for finding in findings:
            category_counts[finding.category] = category_counts.get(finding.category, 0) + 1
        
        if category_counts.get('User Accounts', 0) > 3:
            recommendations.append({
                'priority': 'Medium',
                'title': 'Implement Comprehensive Identity and Access Management',
                'description': 'Multiple user account issues detected affecting compliance frameworks',
                'frameworks_affected': ['PCI_DSS', 'SOC_2', 'ISO_27001'],
                'estimated_effort': 'Medium'
            })
        
        if category_counts.get('Network Security', 0) > 2:
            recommendations.append({
                'priority': 'Medium',
                'title': 'Strengthen Network Security Controls',
                'description': 'Network security gaps detected that impact multiple compliance requirements',
                'frameworks_affected': ['PCI_DSS', 'NIST_CSF'],
                'estimated_effort': 'Medium'
            })
        
        return recommendations


class TrendTracker:
    """Track security trends over time"""
    
    def __init__(self, storage_path: str = "./vigileguard_trends"):
        self.storage_path = Path(storage_path)
        try:
            self.storage_path.mkdir(parents=True, exist_ok=True)
        except PermissionError:
            # Fallback to current directory if we can't create the preferred path
            self.storage_path = Path("./trends")
            self.storage_path.mkdir(parents=True, exist_ok=True)
    
    def record_scan(self, findings: List[Finding], scan_info: Dict[str, Any]) -> str:
        """Record scan results for trend analysis"""
        scan_id = self._generate_scan_id(scan_info)
        
        trend_data = {
            'scan_id': scan_id,
            'timestamp': scan_info.get('timestamp', datetime.now().isoformat()),
            'hostname': scan_info.get('hostname', 'unknown'),
            'summary': self._generate_scan_summary(findings),
            'findings_count': len(findings),
            'categories': self._count_by_category(findings),
            'severities': self._count_by_severity(findings)
        }
        
        # Save to file
        trend_file = self.storage_path / f"scan_{scan_id}.json"
        with open(trend_file, 'w') as f:
            json.dump(trend_data, f, indent=2)
        
        return scan_id
    
    def generate_trend_report(self, hostname: str = None, days: int = 30) -> Dict[str, Any]:
        """Generate trend analysis report"""
        scans = self._load_recent_scans(hostname, days)
        
        if len(scans) < 2:
            return {
                'error': 'Insufficient data for trend analysis',
                'scans_found': len(scans),
                'minimum_required': 2
            }
        
        trend_report = {
            'analysis_period': f"{days} days",
            'total_scans': len(scans),
            'hostname_filter': hostname,
            'trends': {
                'overall': self._analyze_overall_trend(scans),
                'by_category': self._analyze_category_trends(scans),
                'by_severity': self._analyze_severity_trends(scans)
            },
            'recommendations': self._generate_trend_recommendations(scans)
        }
        
        return trend_report
    
    def _generate_scan_id(self, scan_info: Dict[str, Any]) -> str:
        """Generate unique scan ID"""
        hostname = scan_info.get('hostname', 'unknown')
        timestamp = scan_info.get('timestamp', datetime.now().isoformat())
        
        # Create hash from hostname and timestamp
        hash_input = f"{hostname}_{timestamp}".encode()
        return hashlib.md5(hash_input).hexdigest()[:12]
    
    def _generate_scan_summary(self, findings: List[Finding]) -> Dict[str, Any]:
        """Generate summary of scan results"""
        return {
            'total_findings': len(findings),
            'risk_score': self._calculate_risk_score(findings),
            'categories_affected': len(set(f.category for f in findings)),
            'highest_severity': max([f.severity.value for f in findings], default='INFO')
        }
    
    def _calculate_risk_score(self, findings: List[Finding]) -> int:
        """Calculate numerical risk score"""
        severity_weights = {
            'CRITICAL': 10,
            'HIGH': 7,
            'MEDIUM': 4,
            'LOW': 2,
            'INFO': 1
        }
        
        score = sum(severity_weights.get(f.severity.value, 1) for f in findings)
        return min(score, 100)  # Cap at 100
    
    def _count_by_category(self, findings: List[Finding]) -> Dict[str, int]:
        """Count findings by category"""
        counts = {}
        for finding in findings:
            counts[finding.category] = counts.get(finding.category, 0) + 1
        return counts
    
    def _count_by_severity(self, findings: List[Finding]) -> Dict[str, int]:
        """Count findings by severity"""
        counts = {}
        for finding in findings:
            severity = finding.severity.value
            counts[severity] = counts.get(severity, 0) + 1
        return counts
    
    def _load_recent_scans(self, hostname: str = None, days: int = 30) -> List[Dict[str, Any]]:
        """Load recent scan data"""
        cutoff_date = datetime.now() - timedelta(days=days)
        scans = []
        
        for scan_file in self.storage_path.glob("scan_*.json"):
            try:
                with open(scan_file, 'r') as f:
                    scan_data = json.load(f)
                
                # Parse timestamp
                scan_timestamp = datetime.fromisoformat(scan_data['timestamp'].replace('Z', '+00:00'))
                
                # Filter by date and hostname
                if scan_timestamp >= cutoff_date:
                    if hostname is None or scan_data.get('hostname') == hostname:
                        scans.append(scan_data)
                        
            except (json.JSONDecodeError, KeyError, ValueError):
                continue
        
        # Sort by timestamp
        scans.sort(key=lambda x: x['timestamp'])
        return scans
    
    def _analyze_overall_trend(self, scans: List[Dict[str, Any]]) -> Dict[str, Any]:
        """Analyze overall security trend"""
        if len(scans) < 2:
            return {'trend': 'insufficient_data'}
        
        first_scan = scans[0]
        last_scan = scans[-1]
        
        findings_change = last_scan['findings_count'] - first_scan['findings_count']
        risk_change = last_scan['summary']['risk_score'] - first_scan['summary']['risk_score']
        
        if findings_change < 0 and risk_change < 0:
            trend = 'improving'
        elif findings_change > 0 or risk_change > 0:
            trend = 'deteriorating'
        else:
            trend = 'stable'
        
        return {
            'trend': trend,
            'findings_change': findings_change,
            'risk_score_change': risk_change,
            'period_start': first_scan['timestamp'],
            'period_end': last_scan['timestamp'],
            'total_scans_analyzed': len(scans)
        }
    
    def _analyze_category_trends(self, scans: List[Dict[str, Any]]) -> Dict[str, Dict[str, Any]]:
        """Analyze trends by category"""
        category_trends = {}
        
        # Get all categories
        all_categories = set()
        for scan in scans:
            all_categories.update(scan['categories'].keys())
        
        for category in all_categories:
            category_data = []
            for scan in scans:
                count = scan['categories'].get(category, 0)
                category_data.append(count)
            
            if len(category_data) >= 2:
                change = category_data[-1] - category_data[0]
                avg_count = sum(category_data) / len(category_data)
                
                category_trends[category] = {
                    'change': change,
                    'average_count': round(avg_count, 2),
                    'trend': 'improving' if change < 0 else 'deteriorating' if change > 0 else 'stable'
                }
        
        return category_trends
    
    def _analyze_severity_trends(self, scans: List[Dict[str, Any]]) -> Dict[str, Dict[str, Any]]:
        """Analyze trends by severity"""
        severity_trends = {}
        severities = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'INFO']
        
        for severity in severities:
            severity_data = []
            for scan in scans:
                count = scan['severities'].get(severity, 0)
                severity_data.append(count)
            
            if len(severity_data) >= 2:
                change = severity_data[-1] - severity_data[0]
                avg_count = sum(severity_data) / len(severity_data)
                
                severity_trends[severity] = {
                    'change': change,
                    'average_count': round(avg_count, 2),
                    'trend': 'improving' if change < 0 else 'deteriorating' if change > 0 else 'stable'
                }
        
        return severity_trends
    
    def _generate_trend_recommendations(self, scans: List[Dict[str, Any]]) -> List[Dict[str, str]]:
        """Generate recommendations based on trends"""
        recommendations = []
        
        if len(scans) < 2:
            return recommendations
        
        # Check for increasing critical/high issues
        latest_scan = scans[-1]
        previous_scan = scans[-2] if len(scans) >= 2 else scans[0]
        
        critical_high_latest = latest_scan['severities'].get('CRITICAL', 0) + latest_scan['severities'].get('HIGH', 0)
        critical_high_previous = previous_scan['severities'].get('CRITICAL', 0) + previous_scan['severities'].get('HIGH', 0)
        
        if critical_high_latest > critical_high_previous:
            recommendations.append({
                'priority': 'High',
                'title': 'Critical/High severity issues increasing',
                'description': f'Critical and high severity issues increased from {critical_high_previous} to {critical_high_latest}',
                'action': 'Immediate attention required to address new critical security issues'
            })
        
        # Check for consistently high risk scores
        recent_risk_scores = [scan['summary']['risk_score'] for scan in scans[-5:]]
        avg_risk = sum(recent_risk_scores) / len(recent_risk_scores)
        
        if avg_risk > 70:
            recommendations.append({
                'priority': 'High',
                'title': 'Consistently high risk scores',
                'description': f'Average risk score over recent scans: {avg_risk:.1f}/100',
                'action': 'Implement comprehensive security improvements to reduce overall risk'
            })
        
        # Check for new categories appearing
        if len(scans) >= 3:
            old_categories = set(scans[0]['categories'].keys())
            new_categories = set(latest_scan['categories'].keys()) - old_categories
            
            if new_categories:
                recommendations.append({
                    'priority': 'Medium',
                    'title': 'New security categories detected',
                    'description': f'New security issue categories: {", ".join(new_categories)}',
                    'action': 'Review and address newly identified security domains'
                })
        
        return recommendations


class ReportManager:
    """Manage different types of security reports"""
    
    def __init__(self, findings: List[Finding], scan_info: Dict[str, Any]):
        self.findings = findings
        self.scan_info = scan_info
        self.html_reporter = HTMLReporter(findings, scan_info)
        self.compliance_mapper = ComplianceMapper()
        self.trend_tracker = TrendTracker()
    
    def generate_executive_summary(self) -> Dict[str, Any]:
        """Generate executive summary for leadership"""
        summary = {
            'scan_overview': {
                'timestamp': self.scan_info.get('timestamp'),
                'hostname': self.scan_info.get('hostname'),
                'total_findings': len(self.findings),
                'scan_duration': 'Not tracked'  # Could be added in future
            },
            'risk_assessment': self._calculate_risk_assessment(),
            'top_priorities': self._get_top_priorities(),
            'compliance_impact': self._assess_compliance_impact(),
            'resource_requirements': self._estimate_resource_requirements(),
            'executive_recommendations': self._generate_executive_recommendations()
        }
        
        return summary
    
    def generate_technical_report(self, include_trends: bool = True) -> Dict[str, Any]:
        """Generate detailed technical report"""
        report = {
            'scan_metadata': self.scan_info,
            'findings_summary': self._generate_detailed_summary(),
            'detailed_findings': [finding.to_dict() for finding in self.findings],
            'compliance_mapping': self.compliance_mapper.generate_compliance_report(self.findings),
            'remediation_guide': self._generate_remediation_guide(),
            'appendices': {
                'methodology': self._get_methodology_description(),
                'references': self._get_security_references()
            }
        }
        
        if include_trends:
            # Record current scan for trend analysis
            self.trend_tracker.record_scan(self.findings, self.scan_info)
            # Add trend analysis if available
            trend_report = self.trend_tracker.generate_trend_report(
                hostname=self.scan_info.get('hostname')
            )
            if 'error' not in trend_report:
                report['trend_analysis'] = trend_report
        
        return report
    
    def generate_all_formats(self, output_dir: str) -> Dict[str, str]:
        """Generate reports in all available formats"""
        output_path = Path(output_dir)
        output_path.mkdir(parents=True, exist_ok=True)
        
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        hostname = self.scan_info.get('hostname', 'unknown')
        
        generated_files = {}
        
        # HTML Report
        html_file = output_path / f"vigileguard_report_{hostname}_{timestamp}.html"
        self.html_reporter.generate_report(str(html_file))
        generated_files['html'] = str(html_file)
        
        # JSON Technical Report
        json_file = output_path / f"vigileguard_technical_{hostname}_{timestamp}.json"
        technical_report = self.generate_technical_report()
        with open(json_file, 'w') as f:
            json.dump(technical_report, f, indent=2, default=str)
        generated_files['json'] = str(json_file)
        
        # Executive Summary
        executive_file = output_path / f"vigileguard_executive_{hostname}_{timestamp}.json"
        executive_summary = self.generate_executive_summary()
        with open(executive_file, 'w') as f:
            json.dump(executive_summary, f, indent=2, default=str)
        generated_files['executive'] = str(executive_file)
        
        # Compliance Report
        compliance_file = output_path / f"vigileguard_compliance_{hostname}_{timestamp}.json"
        compliance_report = self.compliance_mapper.generate_compliance_report(self.findings)
        with open(compliance_file, 'w') as f:
            json.dump(compliance_report, f, indent=2, default=str)
        generated_files['compliance'] = str(compliance_file)
        
        return generated_files
    
    def _calculate_risk_assessment(self) -> Dict[str, Any]:
        """Calculate overall risk assessment"""
        severity_counts = {}
        for finding in self.findings:
            severity = finding.severity.value
            severity_counts[severity] = severity_counts.get(severity, 0) + 1
        
        # Calculate risk score
        severity_weights = {'CRITICAL': 10, 'HIGH': 7, 'MEDIUM': 4, 'LOW': 2, 'INFO': 1}
        risk_score = sum(severity_weights.get(sev, 1) * count for sev, count in severity_counts.items())
        risk_score = min(risk_score, 100)  # Cap at 100
        
        # Determine risk level
        if risk_score >= 80:
            risk_level = "Critical"
        elif risk_score >= 60:
            risk_level = "High"
        elif risk_score >= 40:
            risk_level = "Medium"
        elif risk_score >= 20:
            risk_level = "Low"
        else:
            risk_level = "Minimal"
        
        return {
            'overall_risk_score': risk_score,
            'risk_level': risk_level,
            'severity_breakdown': severity_counts,
            'risk_factors': self._identify_risk_factors()
        }
    
    def _identify_risk_factors(self) -> List[str]:
        """Identify key risk factors"""
        risk_factors = []
        
        # Check for critical/high issues
        critical_high = sum(1 for f in self.findings if f.severity in [SeverityLevel.CRITICAL, SeverityLevel.HIGH])
        if critical_high > 5:
            risk_factors.append(f"High number of critical/high severity issues ({critical_high})")
        
        # Check for specific high-risk categories
        category_counts = {}
        for finding in self.findings:
            category_counts[finding.category] = category_counts.get(finding.category, 0) + 1
        
        if category_counts.get('Network Security', 0) > 3:
            risk_factors.append("Multiple network security vulnerabilities")
        
        if category_counts.get('Web Server', 0) > 2:
            risk_factors.append("Web server security misconfigurations")
        
        if category_counts.get('User Accounts', 0) > 3:
            risk_factors.append("User account security issues")
        
        return risk_factors
    
    def _get_top_priorities(self) -> List[Dict[str, Any]]:
        """Get top priority issues for executive attention"""
        # Sort by severity and select top issues
        priority_findings = sorted(
            self.findings, 
            key=lambda x: ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'INFO'].index(x.severity.value)
        )[:5]
        
        priorities = []
        for finding in priority_findings:
            priorities.append({
                'title': finding.title,
                'severity': finding.severity.value,
                'category': finding.category,
                'business_impact': self._assess_business_impact(finding),
                'estimated_effort': self._estimate_remediation_effort(finding)
            })
        
        return priorities
    
    def _assess_business_impact(self, finding: Finding) -> str:
        """Assess business impact of a finding"""
        if finding.severity == SeverityLevel.CRITICAL:
            return "High - Immediate risk to business operations"
        elif finding.severity == SeverityLevel.HIGH:
            return "Medium-High - Significant security risk"
        elif finding.severity == SeverityLevel.MEDIUM:
            return "Medium - Moderate security concern"
        elif finding.severity == SeverityLevel.LOW:
            return "Low - Minor security improvement"
        else:
            return "Minimal - Informational"
    
    def _estimate_remediation_effort(self, finding: Finding) -> str:
        """Estimate effort required to remediate finding"""
        # Simple heuristic based on category and severity
        category = finding.category
        severity = finding.severity
        
        if category == "User Accounts" and severity in [SeverityLevel.CRITICAL, SeverityLevel.HIGH]:
            return "Medium - Policy and process changes required"
        elif category == "Network Security":
            return "Low-Medium - Configuration changes"
        elif category == "Web Server":
            return "Low - Configuration updates"
        elif category == "File Permissions":
            return "Low - Permission adjustments"
        else:
            return "Variable - Depends on specific issue"
    
    def _assess_compliance_impact(self) -> Dict[str, Any]:
        """Assess impact on compliance frameworks"""
        compliance_report = self.compliance_mapper.generate_compliance_report(self.findings)
        
        impact_summary = {
            'frameworks_affected': len(compliance_report['frameworks']),
            'highest_impact_framework': None,
            'compliance_risk_level': 'Low'
        }
        
        # Find framework with highest impact
        max_affected_controls = 0
        for framework, data in compliance_report['frameworks'].items():
            affected_controls = data['total_controls_affected']
            if affected_controls > max_affected_controls:
                max_affected_controls = affected_controls
                impact_summary['highest_impact_framework'] = framework
        
        # Determine compliance risk level
        if max_affected_controls > 10:
            impact_summary['compliance_risk_level'] = 'High'
        elif max_affected_controls > 5:
            impact_summary['compliance_risk_level'] = 'Medium'
        
        impact_summary['details'] = compliance_report['coverage_summary']
        
        return impact_summary
    
    def _estimate_resource_requirements(self) -> Dict[str, Any]:
        """Estimate resources needed for remediation"""
        critical_high_count = sum(1 for f in self.findings if f.severity in [SeverityLevel.CRITICAL, SeverityLevel.HIGH])
        medium_count = sum(1 for f in self.findings if f.severity == SeverityLevel.MEDIUM)
        
        # Simple estimation model
        estimated_hours = (critical_high_count * 4) + (medium_count * 2)
        estimated_weeks = max(1, estimated_hours // 40)
        
        return {
            'estimated_remediation_hours': estimated_hours,
            'estimated_timeline_weeks': estimated_weeks,
            'recommended_team_size': min(3, max(1, critical_high_count // 3)),
            'skills_required': self._identify_required_skills(),
            'budget_impact': 'Medium' if estimated_hours > 40 else 'Low'
        }
    
    def _identify_required_skills(self) -> List[str]:
        """Identify skills needed for remediation"""
        skills = set()
        
        categories = set(f.category for f in self.findings)
        
        if 'Network Security' in categories:
            skills.add('Network Administration')
        if 'Web Server' in categories:
            skills.add('Web Server Administration')
        if 'User Accounts' in categories:
            skills.add('Identity and Access Management')
        if 'File Permissions' in categories:
            skills.add('Linux System Administration')
        
        return list(skills)
    
    def _generate_executive_recommendations(self) -> List[Dict[str, str]]:
        """Generate high-level recommendations for executives"""
        recommendations = []
        
        critical_count = sum(1 for f in self.findings if f.severity == SeverityLevel.CRITICAL)
        if critical_count > 0:
            recommendations.append({
                'priority': 'Immediate',
                'recommendation': 'Address Critical Security Issues',
                'description': f'Immediately remediate {critical_count} critical security issues',
                'business_justification': 'Critical issues pose immediate risk to business operations and data security'
            })
        
        # Check for systemic issues
        category_counts = {}
        for finding in self.findings:
            category_counts[finding.category] = category_counts.get(finding.category, 0) + 1
        
        if max(category_counts.values()) > 5:
            top_category = max(category_counts, key=category_counts.get)
            recommendations.append({
                'priority': 'High',
                'recommendation': f'Implement Systematic {top_category} Improvements',
                'description': f'Address systemic issues in {top_category} ({category_counts[top_category]} findings)',
                'business_justification': 'Multiple issues in same area indicate need for systematic approach'
            })
        
        return recommendations
    
    def _generate_detailed_summary(self) -> Dict[str, Any]:
        """Generate detailed findings summary"""
        summary = {
            'total_findings': len(self.findings),
            'by_severity': {},
            'by_category': {},
            'risk_distribution': {},
            'remediation_complexity': {}
        }
        
        # Count by severity
        for finding in self.findings:
            severity = finding.severity.value
            summary['by_severity'][severity] = summary['by_severity'].get(severity, 0) + 1
            
            category = finding.category
            summary['by_category'][category] = summary['by_category'].get(category, 0) + 1
        
        # Risk distribution
        high_risk_findings = [f for f in self.findings if f.severity in [SeverityLevel.CRITICAL, SeverityLevel.HIGH]]
        summary['risk_distribution'] = {
            'high_risk_percentage': round((len(high_risk_findings) / len(self.findings)) * 100, 1) if self.findings else 0,
            'most_critical_category': max(summary['by_category'], key=summary['by_category'].get) if summary['by_category'] else None
        }
        
        return summary
    
    def _generate_remediation_guide(self) -> Dict[str, Any]:
        """Generate comprehensive remediation guide"""
        guide = {
            'quick_wins': [],
            'medium_term_projects': [],
            'long_term_initiatives': [],
            'resource_allocation': {},
            'implementation_timeline': {}
        }
        
        # Categorize findings by remediation complexity
        for finding in self.findings:
            complexity = self._assess_remediation_complexity(finding)
            priority_item = {
                'title': finding.title,
                'category': finding.category,
                'severity': finding.severity.value,
                'recommendation': finding.recommendation,
                'estimated_effort': complexity['effort'],
                'dependencies': complexity['dependencies']
            }
            
            if complexity['timeline'] == 'immediate':
                guide['quick_wins'].append(priority_item)
            elif complexity['timeline'] == 'medium':
                guide['medium_term_projects'].append(priority_item)
            else:
                guide['long_term_initiatives'].append(priority_item)
        
        return guide
    
    def _assess_remediation_complexity(self, finding: Finding) -> Dict[str, Any]:
        """Assess complexity of remediating a specific finding"""
        category = finding.category
        severity = finding.severity
        
        # Default complexity assessment
        complexity = {
            'effort': 'Low',
            'timeline': 'immediate',
            'dependencies': []
        }
        
        if category == 'User Accounts':
            complexity['effort'] = 'Medium'
            complexity['timeline'] = 'medium'
            complexity['dependencies'] = ['Policy Review', 'User Training']
        elif category == 'Network Security' and severity in [SeverityLevel.CRITICAL, SeverityLevel.HIGH]:
            complexity['effort'] = 'Medium'
            complexity['timeline'] = 'immediate'
            complexity['dependencies'] = ['Network Team', 'Change Management']
        elif category == 'Web Server':
            complexity['effort'] = 'Low'
            complexity['timeline'] = 'immediate'
            complexity['dependencies'] = ['Web Team', 'Testing']
        
        return complexity
    
    def _get_methodology_description(self) -> str:
        """Get methodology description for report appendix"""
        return """
        VigileGuard Security Audit Methodology:
        
        1. System Discovery: Automated identification of system components, services, and configurations
        2. Configuration Analysis: Review of security-relevant configuration files and settings  
        3. Permission Assessment: Analysis of file, directory, and service permissions
        4. Network Security Review: Evaluation of network services, firewall rules, and exposed ports
        5. Compliance Mapping: Alignment of findings with industry security frameworks
        6. Risk Assessment: Severity scoring based on potential impact and exploitability
        7. Remediation Guidance: Actionable recommendations for issue resolution
        
        The audit covers multiple security domains including access controls, network security,
        web server configurations, and system hardening. All checks are performed using read-only
        operations where possible to minimize impact on production systems.
        """
    
    def _get_security_references(self) -> List[Dict[str, str]]:
        """Get security references for report appendix"""
        return [
            {
                'title': 'NIST Cybersecurity Framework',
                'url': 'https://www.nist.gov/cyberframework',
                'description': 'Framework for improving critical infrastructure cybersecurity'
            },
            {
                'title': 'OWASP Security Guidelines',
                'url': 'https://owasp.org/',
                'description': 'Open Web Application Security Project guidelines and best practices'
            },
            {
                'title': 'CIS Controls',
                'url': 'https://www.cisecurity.org/controls/',
                'description': 'Center for Internet Security Critical Security Controls'
            },
            {
                'title': 'Linux Security Best Practices',
                'url': 'https://linux-audit.com/linux-security-guide/',
                'description': 'Comprehensive Linux security hardening guide'
            }
        ]