"""
Blockchain Performance Benchmark

Measures blockchain ledger performance metrics.
"""

import time
import json
from typing import Dict, List
from pathlib import Path

from altrus.core.ledger.blockchain import BlockchainLedger
from altrus.core.ledger.storage import LedgerStorage


class BlockchainBenchmark:
    """
    Benchmark blockchain ledger performance.

    Metrics:
    - Transactions per second (TPS)
    - Block write latency
    - Verification time
    - Storage size
    """

    def __init__(self, output_dir: str = "results/benchmarks"):
        self.output_dir = Path(output_dir)
        self.output_dir.mkdir(parents=True, exist_ok=True)
        self.results: Dict = {}

    def benchmark_write_throughput(
        self,
        num_transactions: int = 1000
    ) -> Dict:
        """
        Benchmark block write throughput.

        Args:
            num_transactions: Number of transactions to write

        Returns:
            Dict with TPS and latency metrics
        """
        print(f"📊 Benchmarking write throughput ({num_transactions} transactions)...")

        # Create fresh ledger
        storage = LedgerStorage(storage_dir=str(self.output_dir / "benchmark_ledger"))
        ledger = BlockchainLedger(storage=storage)

        latencies = []
        start_time = time.time()

        for i in range(num_transactions):
            tx_start = time.time()

            ledger.log_event(
                event_type="BENCHMARK_EVENT",
                actor_type="BENCHMARK",
                actor_id=f"tx_{i}",
                data={"index": i, "payload": "x" * 100}
            )

            tx_end = time.time()
            latencies.append(tx_end - tx_start)

        end_time = time.time()
        total_time = end_time - start_time

        results = {
            "num_transactions": num_transactions,
            "total_time_seconds": total_time,
            "tps": num_transactions / total_time,
            "avg_latency_ms": (sum(latencies) / len(latencies)) * 1000,
            "min_latency_ms": min(latencies) * 1000,
            "max_latency_ms": max(latencies) * 1000,
            "p50_latency_ms": sorted(latencies)[len(latencies) // 2] * 1000,
            "p95_latency_ms": sorted(latencies)[int(len(latencies) * 0.95)] * 1000,
            "p99_latency_ms": sorted(latencies)[int(len(latencies) * 0.99)] * 1000,
        }

        print(f"✅ TPS: {results['tps']:.2f}")
        print(f"✅ Avg Latency: {results['avg_latency_ms']:.2f}ms")

        self.results["write_throughput"] = results
        return results

    def benchmark_verification_time(
        self,
        chain_length: int = 1000
    ) -> Dict:
        """
        Benchmark chain verification time.

        Args:
            chain_length: Number of blocks in chain

        Returns:
            Dict with verification metrics
        """
        print(f"📊 Benchmarking verification time ({chain_length} blocks)...")

        # Create chain
        storage = LedgerStorage(storage_dir=str(self.output_dir / "verify_ledger"))
        ledger = BlockchainLedger(storage=storage)

        for i in range(chain_length):
            ledger.log_event(
                event_type="TEST_EVENT",
                actor_type="TEST",
                actor_id=f"block_{i}",
                data={"index": i}
            )

        # Benchmark verification
        from altrus.core.ledger.verifier import BlockchainVerifier
        verifier = BlockchainVerifier(ledger)

        start_time = time.time()
        is_valid = verifier.verify_chain()
        end_time = time.time()

        verification_time = end_time - start_time

        results = {
            "chain_length": chain_length,
            "verification_time_seconds": verification_time,
            "blocks_per_second": chain_length / verification_time,
            "is_valid": is_valid
        }

        print(f"✅ Verification Time: {verification_time:.3f}s")
        print(f"✅ Blocks/sec: {results['blocks_per_second']:.2f}")

        self.results["verification"] = results
        return results

    def benchmark_storage_size(
        self,
        num_blocks: int = 1000
    ) -> Dict:
        """
        Benchmark storage size growth.

        Args:
            num_blocks: Number of blocks to create

        Returns:
            Dict with storage metrics
        """
        print(f"📊 Benchmarking storage size ({num_blocks} blocks)...")

        storage_dir = self.output_dir / "storage_ledger"
        storage = LedgerStorage(storage_dir=str(storage_dir))
        ledger = BlockchainLedger(storage=storage)

        for i in range(num_blocks):
            ledger.log_event(
                event_type="STORAGE_TEST",
                actor_type="TEST",
                actor_id=f"block_{i}",
                data={"index": i, "data": "x" * 200}
            )

        # Calculate storage size
        storage_file = storage_dir / "blockchain.json"
        if storage_file.exists():
            storage_bytes = storage_file.stat().st_size
        else:
            storage_bytes = 0

        results = {
            "num_blocks": num_blocks,
            "storage_bytes": storage_bytes,
            "storage_kb": storage_bytes / 1024,
            "storage_mb": storage_bytes / (1024 * 1024),
            "bytes_per_block": storage_bytes / num_blocks if num_blocks > 0 else 0
        }

        print(f"✅ Storage Size: {results['storage_mb']:.2f} MB")
        print(f"✅ Per Block: {results['bytes_per_block']:.2f} bytes")

        self.results["storage"] = results
        return results

    def run_all_benchmarks(self) -> Dict:
        """Run all benchmarks and generate report"""
        print("🚀 Running all blockchain benchmarks...\n")

        self.benchmark_write_throughput(num_transactions=1000)
        print()

        self.benchmark_verification_time(chain_length=1000)
        print()

        self.benchmark_storage_size(num_blocks=1000)
        print()

        # Save results
        self.save_results()

        return self.results

    def save_results(self):
        """Save benchmark results to JSON file"""
        output_file = self.output_dir / "benchmark_results.json"

        with open(output_file, 'w') as f:
            json.dump(self.results, f, indent=2)

        print(f"💾 Results saved to: {output_file}")

        # Also create a human-readable report
        self.generate_report()

    def generate_report(self):
        """Generate human-readable benchmark report"""
        report_file = self.output_dir / "benchmark_report.txt"

        with open(report_file, 'w') as f:
            f.write("=" * 60 + "\n")
            f.write("ALTRUS BLOCKCHAIN PERFORMANCE BENCHMARK REPORT\n")
            f.write("=" * 60 + "\n\n")

            if "write_throughput" in self.results:
                wt = self.results["write_throughput"]
                f.write("Write Throughput:\n")
                f.write(f"  Transactions: {wt['num_transactions']}\n")
                f.write(f"  TPS: {wt['tps']:.2f}\n")
                f.write(f"  Avg Latency: {wt['avg_latency_ms']:.2f}ms\n")
                f.write(f"  P95 Latency: {wt['p95_latency_ms']:.2f}ms\n")
                f.write(f"  P99 Latency: {wt['p99_latency_ms']:.2f}ms\n\n")

            if "verification" in self.results:
                v = self.results["verification"]
                f.write("Verification Performance:\n")
                f.write(f"  Chain Length: {v['chain_length']} blocks\n")
                f.write(f"  Verification Time: {v['verification_time_seconds']:.3f}s\n")
                f.write(f"  Blocks/sec: {v['blocks_per_second']:.2f}\n")
                f.write(f"  Valid: {v['is_valid']}\n\n")

            if "storage" in self.results:
                s = self.results["storage"]
                f.write("Storage Efficiency:\n")
                f.write(f"  Blocks: {s['num_blocks']}\n")
                f.write(f"  Total Size: {s['storage_mb']:.2f} MB\n")
                f.write(f"  Per Block: {s['bytes_per_block']:.2f} bytes\n\n")

            f.write("=" * 60 + "\n")

        print(f"📄 Report saved to: {report_file}")


def main():
    """Run benchmarks from command line"""
    benchmark = BlockchainBenchmark()
    benchmark.run_all_benchmarks()

    print("\n✅ All benchmarks complete!")


if __name__ == "__main__":
    main()
