"""
Analysis and Visualization for Static vs Dynamic Simulation Comparison.

This module compares results between static (no mobility) and dynamic (with mobility)
network simulations, generating comparison metrics and visualizations.
"""

import json
import csv
from pathlib import Path
from typing import Dict, List, Tuple
import matplotlib.pyplot as plt
import numpy as np


class StaticDynamicAnalyzer:
    """
    Compare static and dynamic simulation results.

    Loads JSON results from both modes and generates:
    - Comparison tables
    - Impact metrics (percentage differences)
    - Visualization graphs
    """

    def __init__(self, dynamic_file: str, static_file: str):
        """
        Initialize analyzer with result files.

        Args:
            dynamic_file: Path to dynamic simulation JSON results
            static_file: Path to static simulation JSON results
        """
        self.dynamic_results = self._load_json(dynamic_file)
        self.static_results = self._load_json(static_file)
        self.comparison_data = {}

    @staticmethod
    def _load_json(filepath: str) -> Dict:
        """Load and return JSON results (DRY: single loading method)."""
        try:
            with open(filepath, 'r') as f:
                return json.load(f)
        except FileNotFoundError:
            print(f"Warning: {filepath} not found")
            return {}

    def _extract_metric(self, results: Dict, scenario: str, protocol: str, metric: str):
        """Extract a single metric (DRY pattern)."""
        try:
            return results[scenario][protocol]['metrics'].get(metric)
        except (KeyError, TypeError):
            return None

    def compute_comparison(self) -> Dict:
        """
        Compute static vs dynamic comparison for all scenarios.

        Returns:
            Dict: Comparison data with impact percentages
        """
        metrics_to_compare = [
            'first_dead_node_round',
            'first_muted_round',
            'dlbi',
            'rspi',
            'final_alive_nodes'
        ]

        comparison = {}

        # Get all scenario names from dynamic results
        for scenario in self.dynamic_results.keys():
            comparison[scenario] = {'LEACH': {}, 'LEACH-C': {}}

            for protocol in ['LEACH', 'LEACH-C']:
                for metric in metrics_to_compare:
                    dyn = self._extract_metric(self.dynamic_results, scenario, protocol, metric)
                    stat = self._extract_metric(self.static_results, scenario, protocol, metric)

                    # Compute impact (percentage difference)
                    if isinstance(dyn, (int, float)) and isinstance(stat, (int, float)):
                        if stat != 0:
                            impact = ((dyn - stat) / stat) * 100
                        else:
                            impact = 0
                    else:
                        impact = None

                    comparison[scenario][protocol][metric] = {
                        'dynamic': dyn,
                        'static': stat,
                        'impact_pct': impact
                    }

        self.comparison_data = comparison
        return comparison

    def generate_csv_report(self, output_file: str = "comparison_static_dynamic.csv"):
        """
        Generate CSV report of static vs dynamic comparison.

        Args:
            output_file: Output CSV filename
        """
        with open(output_file, 'w', newline='') as f:
            writer = csv.writer(f)
            writer.writerow([
                'Scenario', 'Protocol', 'Metric',
                'Dynamic', 'Static', 'Impact(%)'
            ])

            for scenario, protocols in self.comparison_data.items():
                for protocol, metrics in protocols.items():
                    for metric, values in metrics.items():
                        writer.writerow([
                            scenario,
                            protocol,
                            metric,
                            values.get('dynamic', 'N/A'),
                            values.get('static', 'N/A'),
                            f"{values.get('impact_pct', 'N/A'):.2f}" if values.get('impact_pct') is not None else 'N/A'
                        ])

        print(f"CSV report generated: {output_file}")

    def plot_comparison(self, metric: str = 'first_dead_node_round', output_file: str = None):
        """
        Generate comparison bar chart for a metric.

        Args:
            metric: Metric to compare
            output_file: Output PNG filename (optional)
        """
        scenarios = list(self.comparison_data.keys())
        leach_dynamic = []
        leach_static = []
        leachc_dynamic = []
        leachc_static = []

        for scenario in scenarios:
            leach_dyn = self.comparison_data[scenario]['LEACH'][metric]['dynamic']
            leach_stat = self.comparison_data[scenario]['LEACH'][metric]['static']
            leachc_dyn = self.comparison_data[scenario]['LEACH-C'][metric]['dynamic']
            leachc_stat = self.comparison_data[scenario]['LEACH-C'][metric]['static']

            # Handle None values
            leach_dynamic.append(leach_dyn if leach_dyn is not None else 0)
            leach_static.append(leach_stat if leach_stat is not None else 0)
            leachc_dynamic.append(leachc_dyn if leachc_dyn is not None else 0)
            leachc_static.append(leachc_stat if leachc_stat is not None else 0)

        x = np.arange(len(scenarios))
        width = 0.2

        fig, ax = plt.subplots(figsize=(12, 6))
        ax.bar(x - 1.5*width, leach_dynamic, width, label='LEACH Dynamic')
        ax.bar(x - 0.5*width, leach_static, width, label='LEACH Static')
        ax.bar(x + 0.5*width, leachc_dynamic, width, label='LEACH-C Dynamic')
        ax.bar(x + 1.5*width, leachc_static, width, label='LEACH-C Static')

        ax.set_xlabel('Scenario')
        ax.set_ylabel(metric.replace('_', ' ').title())
        ax.set_title(f'Static vs Dynamic Comparison: {metric}')
        ax.set_xticks(x)
        ax.set_xticklabels(scenarios, rotation=45, ha='right')
        ax.legend()
        ax.grid(axis='y', alpha=0.3)

        plt.tight_layout()

        if output_file is None:
            output_file = f"comparison_{metric}.png"

        plt.savefig(output_file, dpi=300)
        print(f"Graph saved: {output_file}")
        plt.close()

    def print_summary(self):
        """Print a summary of static vs dynamic comparison."""
        print("\n" + "="*80)
        print("STATIC VS DYNAMIC COMPARISON SUMMARY")
        print("="*80)

        for scenario in self.comparison_data.keys():
            print(f"\n{scenario}:")
            print("-" * 80)

            for protocol in ['LEACH', 'LEACH-C']:
                metrics = self.comparison_data[scenario][protocol]
                print(f"\n  {protocol}:")

                for metric, values in metrics.items():
                    dyn = values['dynamic']
                    stat = values['static']
                    impact = values['impact_pct']

                    if isinstance(dyn, (int, float)) and isinstance(stat, (int, float)):
                        print(f"    {metric:30s}: Dynamic={dyn:10.2f}, Static={stat:10.2f}, Impact={impact:+.2f}%")
                    else:
                        print(f"    {metric:30s}: Dynamic={dyn}, Static={stat}")


def main():
    """Run static vs dynamic analysis."""
    analyzer = StaticDynamicAnalyzer(
        "results/simulation_results_dynamic.json",
        "results/simulation_results_static.json"
    )

    # Compute comparison
    analyzer.compute_comparison()

    # Generate reports
    analyzer.generate_csv_report("results/comparison_static_dynamic.csv")
    analyzer.print_summary()

    # Generate visualizations for key metrics
    for metric in ['first_dead_node_round', 'first_muted_round', 'dlbi']:
        analyzer.plot_comparison(
            metric,
            output_file=f"results/comparison_{metric}.png"
        )


if __name__ == "__main__":
    main()
