import gradio as gr
import time
from parallel_miner_v3 import ParallelMiner
import threading
import json
from datetime import datetime
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots

# Global variables for mining state
miner_instance = None
mining_thread = None
is_mining = False
stats_history = {
    "timestamps": [],
    "hashrates": [],
    "total_hashes": [],
    "blocks_found": []
}

def update_stats_history(hashrate, total_hashes, blocks):
    """Update historical stats for plotting"""
    current_time = datetime.now().strftime("%H:%M:%S")
    stats_history["timestamps"].append(current_time)
    stats_history["hashrates"].append(hashrate)
    stats_history["total_hashes"].append(total_hashes)
    stats_history["blocks_found"].append(blocks)
    
    # Keep only last 100 data points
    max_points = 100
    if len(stats_history["timestamps"]) > max_points:
        stats_history["timestamps"] = stats_history["timestamps"][-max_points:]
        stats_history["hashrates"] = stats_history["hashrates"][-max_points:]
        stats_history["total_hashes"] = stats_history["total_hashes"][-max_points:]
        stats_history["blocks_found"] = stats_history["blocks_found"][-max_points:]

def create_performance_plots():
    """Create performance visualization plots"""
    fig = make_subplots(
        rows=2, cols=1,
        subplot_titles=("Mining Hashrate (KH/s)", "Total Hashes"),
        vertical_spacing=0.12
    )
    
    # Hashrate plot
    fig.add_trace(
        go.Scatter(x=stats_history["timestamps"], 
                  y=[h/1000 for h in stats_history["hashrates"]], 
                  mode='lines+markers',
                  name='Hashrate',
                  line=dict(color='#2ecc71')),
        row=1, col=1
    )
    
    # Total hashes plot
    fig.add_trace(
        go.Scatter(x=stats_history["timestamps"], 
                  y=stats_history["total_hashes"],
                  mode='lines',
                  name='Total Hashes',
                  line=dict(color='#3498db')),
        row=2, col=1
    )
    
    fig.update_layout(
        height=600,
        showlegend=True,
        title_text="Mining Performance Metrics",
        template="plotly_dark"
    )
    
    return fig

def start_mining():
    """Start the mining process"""
    global miner_instance, mining_thread, is_mining
    
    if is_mining:
        return "Mining is already running!"
    
    try:
        miner_instance = ParallelMiner(num_cores=5)
        miner_instance.mining = True
        is_mining = True
        
        # Start mining in background thread
        mining_thread = threading.Thread(
            target=miner_instance.start_mining,
            kwargs={"duration": None}
        )
        mining_thread.daemon = True
        mining_thread.start()
        
        return "Mining started successfully! Monitor the stats below."
    except Exception as e:
        return f"Error starting mining: {str(e)}"

def stop_mining():
    """Stop the mining process"""
    global miner_instance, is_mining
    
    if not is_mining:
        return "Mining is not running!"
    
    try:
        if miner_instance:
            miner_instance.mining = False
            is_mining = False
            return "Mining stopped successfully!"
        return "No active mining instance found."
    except Exception as e:
        return f"Error stopping mining: {str(e)}"

def get_mining_stats():
    """Get current mining statistics"""
    global miner_instance, is_mining
    
    if not miner_instance or not is_mining:
        return {
            "status": "Stopped",
            "hashrate": "0 H/s",
            "total_hashes": "0",
            "blocks_found": "0",
            "best_hash": "None",
            "difficulty": "0"
        }
    
    # Update historical stats
    update_stats_history(
        miner_instance.current_hashrate,
        miner_instance.total_hashes,
        miner_instance.blocks_found
    )
    
    # Create performance plot
    performance_plot = create_performance_plots()
    
    return {
        "status": "Running" if is_mining else "Stopped",
        "hashrate": f"{miner_instance.current_hashrate/1000:.2f} KH/s",
        "total_hashes": f"{miner_instance.total_hashes:,}",
        "blocks_found": str(miner_instance.blocks_found),
        "best_hash": miner_instance.best_hash.hex() if miner_instance.best_hash else "None",
        "difficulty": f"{miner_instance.best_hash_difficulty:,}",
        "performance_plot": performance_plot
    }

# Create the Gradio interface
with gr.Blocks(theme=gr.themes.Monochrome()) as app:
    gr.Markdown("# ⛏️ Bitcoin Mining Dashboard")
    
    with gr.Row():
        start_btn = gr.Button("▶️ Start Mining", variant="primary")
        stop_btn = gr.Button("⏹️ Stop Mining", variant="secondary")
        refresh_btn = gr.Button("🔄 Refresh", variant="primary")
    
    with gr.Row():
        with gr.Column():
            status_label = gr.Label(label="Status")
            hashrate_label = gr.Label(label="Current Hashrate")
            total_hashes_label = gr.Label(label="Total Hashes")
            blocks_label = gr.Label(label="Blocks Found")
            best_hash_label = gr.Label(label="Best Hash")
            difficulty_label = gr.Label(label="Best Difficulty")
    
    with gr.Row():
        plot_output = gr.Plot(label="Performance Metrics")
    
    def auto_refresh():
        stats = get_mining_stats()
        return [
            stats["status"],
            stats["hashrate"],
            stats["total_hashes"],
            stats["blocks_found"],
            stats["best_hash"],
            stats["difficulty"],
            stats["performance_plot"]
        ]
    
    # Setup event handlers
    start_btn.click(
        fn=start_mining,
        outputs=[status_label]
    ).then(
        fn=auto_refresh,
        outputs=[
            status_label,
            hashrate_label,
            total_hashes_label,
            blocks_label,
            best_hash_label,
            difficulty_label,
            plot_output
        ]
    )
    
    stop_btn.click(
        fn=stop_mining,
        outputs=[status_label]
    ).then(
        fn=auto_refresh,
        outputs=[
            status_label,
            hashrate_label,
            total_hashes_label,
            blocks_label,
            best_hash_label,
            difficulty_label,
            plot_output
        ]
    )
    
    # Manual refresh button with auto-update
    refresh_btn.click(
        fn=auto_refresh,
        outputs=[
            status_label,
            hashrate_label,
            total_hashes_label,
            blocks_label,
            best_hash_label,
            difficulty_label,
            plot_output
        ],
        every=1  # Refresh every second when clicked
    )

if __name__ == "__main__":
    app.launch(
        share=True,  # Enable sharing
        server_name="0.0.0.0",
        server_port=7860
    )