import asyncio
import os
import sys
from typing import Optional
from datetime import datetime

from rich import box
from rich.align import Align
from rich.console import Console, Group
from rich.layout import Layout
from rich.panel import Panel
from rich.prompt import Prompt, IntPrompt
from rich.table import Table
from rich.text import Text
from rich.live import Live
from rich.style import Style

from .sdk import EmpoorioChainConfig, EmpoorioChainSDK, Transaction

console = Console()

LOGO = """
 [bold magenta]███████╗███╗   ███╗██████╗  ██████╗  ██████╗ ██████╗ ██╗ ██████╗ [/bold magenta]
 [bold magenta]██╔════╝████╗ ████║██╔══██╗██╔═══██╗██╔═══██╗██╔══██╗██║██╔═══██╗[/bold magenta]
 [bold magenta]█████╗  ██╔████╔██║██████╔╝██║   ██║██║   ██║██████╔╝██║██║   ██║[/bold magenta]
 [bold magenta]██╔══╝  ██║╚██╔╝██║██╔═══╝ ██║   ██║██║   ██║██╔══██╗██║██║   ██║[/bold magenta]
 [bold magenta]███████╗██║ ╚═╝ ██║██║     ╚██████╔╝╚██████╔╝██║  ██║██║╚██████╔╝[/bold magenta]
 [bold magenta]╚══════╝╚═╝     ╚═╝╚═╝      ╚═════╝  ╚═════╝ ╚═╝  ╚═╝╚═╝ ╚═════╝ [/bold magenta]
                                         [italic cyan]Chain SDK Terminal v0.1.6[/italic cyan]
"""

class DashboardApp:
    def __init__(self):
        self.config: Optional[EmpoorioChainConfig] = self._build_config_from_env()
        self.sdk: Optional[EmpoorioChainSDK] = None
        self.layout = Layout()
        self.connected = False
        
    def _env(self, name: str, default: Optional[str] = None) -> Optional[str]:
        value = os.getenv(name, default)
        return value if value and value.strip() else default

    def _build_config_from_env(self) -> Optional[EmpoorioChainConfig]:
        rpc_url = self._env("EMPOORIO_RPC_URL", "http://127.0.0.1:8545")
        if not rpc_url:
            return None
        ws_url = self._env("EMPOORIO_WS_URL")
        chain_id = int(self._env("EMPOORIO_CHAIN_ID", "1234"))
        return EmpoorioChainConfig(rpc_url=rpc_url, ws_url=ws_url, chain_id=chain_id)

    async def connect(self):
        if not self.config:
            return
        try:
            self.sdk = EmpoorioChainSDK(self.config)
            await self.sdk.connect()
            self.connected = True
        except Exception:
            self.connected = False
            self.sdk = None

    def make_layout(self) -> Layout:
        self.layout.split(
            Layout(name="header", size=10),
            Layout(name="main", ratio=1),
            Layout(name="footer", size=3),
        )
        self.layout["main"].split_row(
            Layout(name="network", ratio=1),
            Layout(name="metrics", ratio=2),
        )
        return self.layout

    async def update_view(self) -> Panel:
        header_text = Text.from_markup(LOGO)
        self.layout["header"].update(Panel(header_text, style="magenta", box=box.HEAVY))
        
        # Footer
        footer_text = Text(" Press Ctrl+C to Exit | Interactive Menu: Select option below ", style="white on blue", justify="center")
        self.layout["footer"].update(Panel(footer_text, box=box.SIMPLE))

        if not self.connected or not self.sdk:
            status_panel = Panel(
                Align.center("[bold red]● OFFLINE[/bold red]\n\n[dim]RPC Connection Failed[/dim]\n[cyan]Retrying...[/cyan]"),
                title="Status",
                border_style="red",
                box=box.ROUNDED
            )
            self.layout["network"].update(status_panel)
            self.layout["metrics"].update(Panel(Align.center("No Data Available"), title="Metrics", border_style="dim", box=box.ROUNDED))
            return Panel(self.layout, title="EmpoorioChain Dashboard", border_style="blue")
        
        # Fetch Data
        try:
            node = await self.sdk.get_node_info()
            latest_block = await self.sdk.get_latest_block()
            gas_price = await self.sdk.get_gas_price()
        except Exception:
             self.connected = False # Lost connection
             return Panel(self.layout, title="Reconnecting...", border_style="red")

        # Network Panel
        is_syncing = node.get("syncing") not in (False, None)
        status_text = "[bold yellow]↻ SYNCING[/bold yellow]" if is_syncing else "[bold green]● ONLINE[/bold green]"
        
        net_table = Table(show_header=False, box=None, expand=True)
        net_table.add_column("Key", style="cyan")
        net_table.add_column("Value", style="bright_white")
        net_table.add_row("Client", str(node.get("client_version")).split("/")[0])
        net_table.add_row("Peers", str(node.get("peer_count")))
        net_table.add_row("ChainID", str(node.get("chain_id")))
        
        net_panel = Panel(
            Align.center(f"{status_text}\n") + net_table,
            title="Network Node",
            border_style="green" if not is_syncing else "yellow",
            box=box.ROUNDED
        )
        self.layout["network"].update(net_panel)

        # Metrics Panel
        chain_table = Table(show_header=True, header_style="bold magenta", box=box.SIMPLE_HEAD, expand=True)
        chain_table.add_column("Metric")
        chain_table.add_column("Value", justify="right")
        
        chain_table.add_row("Block Height", f"[bold cyan]{latest_block.number}[/bold cyan]")
        chain_table.add_row("Block Time", datetime.fromtimestamp(latest_block.timestamp).strftime('%H:%M:%S'))
        chain_table.add_row("Transactions", str(len(latest_block.transactions)))
        chain_table.add_row("Gas Price", f"{gas_price} wei")
        chain_table.add_row("Gas Used", f"{int(latest_block.gas_used):,}")
        
        metrics_panel = Panel(chain_table, title="Blockchain Live Metrics", border_style="magenta", box=box.ROUNDED)
        self.layout["metrics"].update(metrics_panel)

        return Panel(self.layout, title="EmpoorioChain Dashboard", border_style="blue")
    
    async def run_dashboard(self):
        console.clear()
        self.make_layout()
        await self.connect()
        
        # Initial Render
        console.print(await self.update_view())


async def interactive_loop():
    app = DashboardApp()
    await app.connect()

    while True:
        console.clear()
        # Render Dashboard Snapshot
        console.print(await app.update_view())
        
        menu = Table(box=box.ROUNDED, show_header=True, header_style="bold cyan", expand=True)
        menu.add_column("ID", justify="center", style="bold yellow", width=4)
        menu.add_column("Command", style="white")
        menu.add_column("Description", style="dim")
        
        menu.add_row("1", "Refresh", "Reload dashboard data")
        menu.add_row("2", "Connect", "Configure connection settings")
        menu.add_row("3", "Balance", "Check wallet balance")
        menu.add_row("4", "Block Info", "Lookup block details")
        menu.add_row("5", "Tx Info", "Lookup transaction details")
        menu.add_row("6", "Send Tx", "Transfer assets")
        menu.add_row("0", "Exit", "Close terminal")
        
        console.print(menu)
        
        choice = Prompt.ask("[bold cyan]COMMAND[/bold cyan]", choices=[str(i) for i in range(7)], default="1")
        
        if choice == "0":
            console.print("[yellow]Exiting...[/yellow]")
            if app.sdk:
                await app.sdk.disconnect()
            sys.exit(0)
            
        elif choice == "1":
            continue # Loop refreshes
            
        elif choice == "2":
            rpc = Prompt.ask("RPC URL", default="http://127.0.0.1:8545")
            ws = Prompt.ask("WS URL (optional)", default="")
            cid = IntPrompt.ask("Chain ID", default=1234)
            app.config = EmpoorioChainConfig(rpc_url=rpc, ws_url=ws if ws else None, chain_id=cid)
            await app.connect()
            
        elif choice == "3":
            if not app.connected:
                console.print("[red]Not Connected[/red]")
                Prompt.ask("Press Enter")
                continue
            addr = Prompt.ask("Address")
            bal = await app.sdk.get_balance(addr)
            console.print(f"\n[green]Balance:[/green] {bal.balance} {bal.symbol}\n")
            Prompt.ask("Press Enter to continue")
            
        elif choice == "4":
             if not app.connected:
                console.print("[red]Not Connected[/red]")
                Prompt.ask("Press Enter")
                continue
             num = IntPrompt.ask("Block Number")
             blk = await app.sdk.get_block(num)
             console.print(blk)
             Prompt.ask("Press Enter to continue")
             
        elif choice == "5":
             if not app.connected:
                console.print("[red]Not Connected[/red]")
                Prompt.ask("Press Enter")
                continue
             h = Prompt.ask("Tx Hash")
             tx = await app.sdk.get_transaction(h)
             console.print(tx)
             Prompt.ask("Press Enter to continue")
             
        elif choice == "6":
             if not app.connected:
                console.print("[red]Not Connected[/red]")
                Prompt.ask("Press Enter")
                continue
             t = Prompt.ask("To")
             v = Prompt.ask("Value")
             pk = Prompt.ask("Private Key")
             # Simplified for demo
             try:
                 tx_hash = await app.sdk.send_transaction(Transaction("", t, v), pk)
                 console.print(f"[green]Sent:[/green] {tx_hash}")
             except Exception as e:
                 console.print(f"[red]Error:[/red] {e}")
             Prompt.ask("Press Enter to continue")


def main():
    try:
        asyncio.run(interactive_loop())
    except KeyboardInterrupt:
        print("\nGoodbye!")

if __name__ == "__main__":
    main()

