#!/usr/bin/env python3
"""
DragonX RandomX Block Time Calculator

Estimates how long it will take to find a block given your hashrate
and the current network difficulty.

Usage:
    python3 block_time_calculator.py <hashrate_h/s> [--difficulty <diff>]

Examples:
    python3 block_time_calculator.py 1000          # 1000 H/s, auto-fetch difficulty
    python3 block_time_calculator.py 5K             # 5 KH/s
    python3 block_time_calculator.py 1.2M           # 1.2 MH/s
    python3 block_time_calculator.py 500 --difficulty 1234.56
"""

import argparse
import json
import subprocess
import sys

# DragonX chain constants
BLOCK_TIME = 36  # seconds
# powLimit = 0x0f0f0f0f... (32 bytes of 0x0f) = (2^256 - 1) / 17
# The multiplier 2^256 / powLimit ≈ 17
POW_LIMIT_HEX = "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"
POW_LIMIT = int(POW_LIMIT_HEX, 16)
TWO_256 = 2 ** 256


def parse_hashrate(value):
    """Parse hashrate string with optional K/M/G/T suffix."""
    suffixes = {"K": 1e3, "M": 1e6, "G": 1e9, "T": 1e12}
    value = value.strip().upper()
    if value and value[-1] in suffixes:
        return float(value[:-1]) * suffixes[value[-1]]
    return float(value)


def get_difficulty_from_node():
    """Try to fetch current difficulty from a running DragonX node."""
    try:
        result = subprocess.run(
            ["dragonx-cli", "getmininginfo"],
            capture_output=True, text=True, timeout=10
        )
        if result.returncode == 0:
            info = json.loads(result.stdout)
            return float(info["difficulty"])
    except FileNotFoundError:
        pass
    except (subprocess.TimeoutExpired, json.JSONDecodeError, KeyError):
        pass

    # Try with src/ path relative to script location
    try:
        import os
        script_dir = os.path.dirname(os.path.abspath(__file__))
        cli_path = os.path.join(script_dir, "src", "dragonx-cli")
        result = subprocess.run(
            [cli_path, "getmininginfo"],
            capture_output=True, text=True, timeout=10
        )
        if result.returncode == 0:
            info = json.loads(result.stdout)
            return float(info["difficulty"])
    except (FileNotFoundError, subprocess.TimeoutExpired, json.JSONDecodeError, KeyError):
        pass

    return None


def format_duration(seconds):
    """Format seconds into a human-readable duration string."""
    days = seconds / 86400
    if days >= 365:
        years = days / 365.25
        return f"{years:.2f} years ({days:.1f} days)"
    if days >= 1:
        hours = (seconds % 86400) / 3600
        return f"{days:.2f} days ({days * 24:.1f} hours)"
    hours = seconds / 3600
    if hours >= 1:
        return f"{hours:.2f} hours"
    minutes = seconds / 60
    return f"{minutes:.1f} minutes"


def main():
    parser = argparse.ArgumentParser(
        description="DragonX RandomX Block Time Calculator"
    )
    parser.add_argument(
        "hashrate",
        help="Your hashrate in H/s (supports K/M/G/T suffixes, e.g. 5K, 1.2M)"
    )
    parser.add_argument(
        "--difficulty", "-d", type=float, default=None,
        help="Network difficulty (auto-fetched from local node if omitted)"
    )
    args = parser.parse_args()

    try:
        hashrate = parse_hashrate(args.hashrate)
    except ValueError:
        print(f"Error: Invalid hashrate '{args.hashrate}'", file=sys.stderr)
        sys.exit(1)

    if hashrate <= 0:
        print("Error: Hashrate must be positive", file=sys.stderr)
        sys.exit(1)

    difficulty = args.difficulty
    if difficulty is None:
        print("Querying local DragonX node for current difficulty...")
        difficulty = get_difficulty_from_node()
        if difficulty is None:
            print(
                "Error: Could not connect to DragonX node.\n"
                "Make sure dragonxd is running, or pass --difficulty manually.",
                file=sys.stderr
            )
            sys.exit(1)

    if difficulty <= 0:
        print("Error: Difficulty must be positive", file=sys.stderr)
        sys.exit(1)

    # Expected hashes to find a block = 2^256 / current_target
    # Since difficulty = powLimit / current_target:
    #   current_target = powLimit / difficulty
    #   expected_hashes = 2^256 / (powLimit / difficulty) = difficulty * 2^256 / powLimit
    expected_hashes = difficulty * TWO_256 / POW_LIMIT
    time_seconds = expected_hashes / hashrate
    time_days = time_seconds / 86400

    # Estimate network hashrate from difficulty and block time
    network_hashrate = expected_hashes / BLOCK_TIME

    print()
    print("=" * 50)
    print("  DragonX Block Time Estimator (RandomX)")
    print("=" * 50)
    print(f"  Network difficulty : {difficulty:,.4f}")
    print(f"  Your hashrate      : {hashrate:,.0f} H/s")
    print(f"  Est. network hash  : {network_hashrate:,.0f} H/s")
    print(f"  Block time target  : {BLOCK_TIME}s")
    print(f"  Block reward       : 3 DRGX")
    print("-" * 50)
    print(f"  Expected time to find a block:")
    print(f"    {format_duration(time_seconds)}")
    print(f"    ({time_days:.4f} days)")
    print("-" * 50)
    print(f"  Est. blocks/day    : {86400 / time_seconds:.6f}")
    print(f"  Est. DRGX/day      : {86400 / time_seconds * 3:.6f}")
    print("=" * 50)
    print()
    print("Note: This is a statistical estimate. Actual time varies due to randomness.")


if __name__ == "__main__":
    main()
