#!/usr/bin/env python3
"""
═══════════════════════════════════════════════════════════════
  LITCOIN MULTI-AGENT MINING DEMO

  Shows multiple AI agents mining simultaneously with
  diminishing returns, live stats, and a real-time dashboard.

  Usage:
    python -m litcoin.demo                    # 3 agents, default config
    python -m litcoin.demo --agents 5         # 5 agents
    python -m litcoin.demo --rounds 10        # 10 rounds each
    python -m litcoin.demo --config demo.json # custom config

  Each agent gets its own Bankr wallet and mines independently.
  The dashboard shows real-time stats for all agents.
═══════════════════════════════════════════════════════════════
"""

import os
import sys
import json
import time
import threading
import argparse
import logging
from datetime import datetime, timezone

from litcoin.agent import Agent


# ─── Dashboard ────────────────────────────────────────────────────────────────

class Dashboard:
    """Real-time terminal dashboard for multi-agent mining."""

    def __init__(self, agents):
        self.agents = agents
        self.events = []
        self._lock = threading.Lock()
        self._running = False

    def log_event(self, agent_name, event_type, detail):
        with self._lock:
            self.events.append({
                "time": datetime.now(timezone.utc).strftime("%H:%M:%S"),
                "agent": agent_name,
                "type": event_type,
                "detail": detail,
            })
            # Keep last 20 events
            if len(self.events) > 20:
                self.events = self.events[-20:]

    def render(self):
        """Render the dashboard to terminal."""
        lines = []
        lines.append("\033[2J\033[H")  # Clear screen
        lines.append("╔═══════════════════════════════════════════════════════════════╗")
        lines.append("║           LITCOIN MULTI-AGENT MINING DEMO                    ║")
        lines.append("╠═══════════════════════════════════════════════════════════════╣")

        # Agent table
        lines.append("║  Agent           │ Rounds │ Pass │ Fail │ Rate  │ Earned     ║")
        lines.append("║──────────────────┼────────┼──────┼──────┼───────┼────────────║")

        total_rounds = 0
        total_passes = 0
        total_earned = 0

        for agent in self.agents:
            s = agent.stats
            name = agent.name[:16].ljust(16)
            rounds = str(s.rounds).rjust(6)
            passes = str(s.passes).rjust(4)
            fails = str(s.fails).rjust(4)
            rate = f"{s.pass_rate:.0f}%".rjust(5)
            earned = f"{s.total_earned:,}".rjust(10)
            lines.append(f"║  {name} │ {rounds} │ {passes} │ {fails} │ {rate} │ {earned} ║")

            total_rounds += s.rounds
            total_passes += s.passes
            total_earned += s.total_earned

        lines.append("║──────────────────┼────────┼──────┼──────┼───────┼────────────║")
        total_rate = f"{total_passes / max(1, total_rounds) * 100:.0f}%".rjust(5)
        lines.append(f"║  {'TOTAL'.ljust(16)} │ {str(total_rounds).rjust(6)} │ {str(total_passes).rjust(4)} │ {str(total_rounds - total_passes).rjust(4)} │ {total_rate} │ {f'{total_earned:,}'.rjust(10)} ║")

        lines.append("╠═══════════════════════════════════════════════════════════════╣")
        lines.append("║  Event Log                                                   ║")
        lines.append("╠═══════════════════════════════════════════════════════════════╣")

        with self._lock:
            for event in self.events[-10:]:
                icon = "✓" if event["type"] == "pass" else "✗" if event["type"] == "fail" else "·"
                msg = f"  {event['time']} [{event['agent'][:12]}] {icon} {event['detail']}"
                lines.append(f"║{msg[:61].ljust(61)}║")

        # Pad to fill
        while len(lines) < 30:
            lines.append(f"║{''.ljust(61)}║")

        lines.append("╚═══════════════════════════════════════════════════════════════╝")
        lines.append("  Press Ctrl+C to stop all agents")

        print("\n".join(lines), flush=True)

    def run(self, refresh=2.0):
        """Run the dashboard refresh loop."""
        self._running = True
        while self._running:
            try:
                self.render()
                time.sleep(refresh)
            except Exception:
                pass

    def stop(self):
        self._running = False


# ─── Demo Runner ──────────────────────────────────────────────────────────────

def make_callback(dashboard, agent_name):
    """Create a solve callback that updates the dashboard."""
    def on_solve(result):
        if result.get("pass"):
            reward = result.get("reward", 0)
            dashboard.log_event(agent_name, "pass", f"+{reward:,} LITCOIN")
        else:
            dashboard.log_event(agent_name, "fail", "solve failed")
    return on_solve


def run_demo(agent_configs, rounds=0, max_failures=10):
    """
    Run multiple agents simultaneously with a live dashboard.

    Args:
        agent_configs: List of dicts, each with:
            - bankr_key: Bankr API key (required)
            - name: Agent display name (optional)
        rounds: Rounds per agent (0 = run forever)
        max_failures: Max consecutive failures before stopping an agent
    """
    # Create agents
    agents = []
    for i, config in enumerate(agent_configs):
        name = config.get("name", f"Agent-{i+1}")
        agent = Agent(
            bankr_key=config["bankr_key"],
            name=name,
            log_level=logging.WARNING,  # Quiet — dashboard handles display
        )
        agents.append(agent)

    # Create dashboard
    dashboard = Dashboard(agents)

    # Start mining threads
    threads = []
    for agent in agents:
        cb = make_callback(dashboard, agent.name)
        t = agent.mine_async(rounds=rounds, max_failures=max_failures, on_solve=cb, delay=3)
        threads.append(t)
        time.sleep(0.5)  # Stagger starts slightly

    # Run dashboard on main thread
    try:
        dashboard.run()
    except KeyboardInterrupt:
        print("\n\n  Stopping all agents...\n")
        dashboard.stop()
        for agent in agents:
            agent.stop()

    # Wait for threads
    for t in threads:
        t.join(timeout=10)

    # Final summary
    print("\n╔═══════════════════════════════════════════════════════════════╗")
    print("║                    DEMO COMPLETE                             ║")
    print("╠═══════════════════════════════════════════════════════════════╣")
    total = 0
    for agent in agents:
        s = agent.stats
        total += s.total_earned
        print(f"  {agent.name:20s}  {s.passes}/{s.rounds} passed  {s.total_earned:>10,} LITCOIN")
    print(f"  {'TOTAL':20s}  {'':14s}  {total:>10,} LITCOIN")
    print("╚═══════════════════════════════════════════════════════════════╝")


# ─── CLI ──────────────────────────────────────────────────────────────────────

def main():
    parser = argparse.ArgumentParser(description="LITCOIN Multi-Agent Mining Demo")
    parser.add_argument("--agents", type=int, default=3, help="Number of agents (default: 3)")
    parser.add_argument("--rounds", type=int, default=0, help="Rounds per agent (0 = forever)")
    parser.add_argument("--config", type=str, help="JSON config file with agent definitions")
    parser.add_argument("--bankr-key", type=str, help="Single Bankr key (creates N agents with same wallet)")
    args = parser.parse_args()

    if args.config:
        with open(args.config) as f:
            agent_configs = json.load(f)
    elif args.bankr_key:
        agent_configs = [
            {"bankr_key": args.bankr_key, "name": f"Miner-{i+1}"}
            for i in range(args.agents)
        ]
    else:
        # Check environment
        bankr_key = os.environ.get("BANKR_API_KEY")
        if not bankr_key:
            print("""
  ╔═══════════════════════════════════════════════════════════════╗
  ║  LITCOIN MULTI-AGENT MINING DEMO                             ║
  ╠═══════════════════════════════════════════════════════════════╣
  ║                                                               ║
  ║  Usage:                                                       ║
  ║                                                               ║
  ║  1. Set your Bankr key:                                       ║
  ║     export BANKR_API_KEY="bk_YOUR_KEY"                        ║
  ║                                                               ║
  ║  2. Run the demo:                                             ║
  ║     python -m litcoin.demo --agents 3 --rounds 5              ║
  ║                                                               ║
  ║  Or provide a JSON config:                                    ║
  ║     python -m litcoin.demo --config agents.json               ║
  ║                                                               ║
  ║  Config format:                                               ║
  ║  [                                                            ║
  ║    {"bankr_key": "bk_...", "name": "Agent-1"},                ║
  ║    {"bankr_key": "bk_...", "name": "Agent-2"}                 ║
  ║  ]                                                            ║
  ║                                                               ║
  ╚═══════════════════════════════════════════════════════════════╝
""")
            sys.exit(1)

        agent_configs = [
            {"bankr_key": bankr_key, "name": f"Miner-{i+1}"}
            for i in range(args.agents)
        ]

    print(f"\n  Starting {len(agent_configs)} agents, {args.rounds or '∞'} rounds each...\n")
    run_demo(agent_configs, rounds=args.rounds)


if __name__ == "__main__":
    main()
