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
        self.make_layout() # Fix: Initialize layout immediately
        
    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="bold magenta", box=box.DOUBLE_EDGE, padding=(0,1)))
        
        # Footer
        footer_text = Text(" ⚡ EmpoorioChain SDK v0.1.7 | Ctrl+C to Exit ", style="bold white on blue", justify="center")
        self.layout["footer"].update(Panel(footer_text, box=box.SIMPLE, style="on blue"))

        if not self.connected or not self.sdk:
            status_panel = Panel(
                Align.center("\n[bold red]● DISCONNECTED[/bold red]\n\n[dim italic]Unable to reach RPC Node[/dim italic]\n[cyan]Check connection settings[/cyan]"),
                title="[bold red]System Status[/bold red]",
                border_style="red",
                box=box.HEAVY,
                padding=(1, 2)
            )
            # Show empty metrics with placeholders
            metrics_placeholder = Table(box=box.SIMPLE, expand=True, show_header=False)
            metrics_placeholder.add_column(style="dim")
            metrics_placeholder.add_row("Waiting for connection...")
            
            self.layout["network"].update(status_panel)
            self.layout["metrics"].update(Panel(Align.center(metrics_placeholder), title="[bold dim]Metrics[/bold dim]", border_style="dim", box=box.ROUNDED))
            return Panel(self.layout, title="[bold cyan]EmpoorioChain Terminal[/bold cyan]", border_style="cyan", box=box.DOUBLE)
        
        # 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="[bold red]Connection Lost[/bold red]", 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]● NETWORK ACTIVE[/bold green]"
        status_style = "bold yellow" if is_syncing else "bold green"
        
        net_table = Table(show_header=False, box=None, expand=True, padding=(0, 1))
        net_table.add_column("Key", style="cyan bold")
        net_table.add_column("Value", style="white")
        net_table.add_row("Client", str(node.get("client_version")).split("/")[0])
        net_table.add_row("Peers", f"[bold]{node.get('peer_count')}[/bold]")
        net_table.add_row("Chain ID", f"[yellow]{node.get('chain_id')}[/yellow]")
        
        net_panel = Panel(
            Align.center(f"\n{status_text}\n") + net_table,
            title=f"[{status_style}]Network Node[/{status_style}]",
            border_style="green" if not is_syncing else "yellow",
            box=box.ROUNDED,
            padding=(1, 1)
        )
        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", style="dim")
        chain_table.add_column("VALUE", justify="right", style="bold")
        
        chain_table.add_row("Block Height", f"[cyan]{latest_block.number:,}[/cyan]")
        chain_table.add_row("Block Time", datetime.fromtimestamp(latest_block.timestamp).strftime('%H:%M:%S'))
        chain_table.add_row("Transactions", f"[green]{len(latest_block.transactions)}[/green] txs")
        chain_table.add_row("Gas Price", f"[yellow]{gas_price}[/yellow] wei")
        chain_table.add_row("Gas Used", f"{int(latest_block.gas_used):,}")
        
        metrics_panel = Panel(chain_table, title="[bold magenta]Live Metrics[/bold magenta]", border_style="magenta", box=box.ROUNDED)
        self.layout["metrics"].update(metrics_panel)

        return Panel(self.layout, title="[bold cyan]EmpoorioChain Terminal[/bold cyan]", border_style="blue", box=box.DOUBLE)
    
    async def run_dashboard(self):
        console.clear()
        # Ensure layout is ready (though init call covers it)
        if not self.layout.children:
             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 Styling
        menu = Table(box=box.HEAVY_EDGE, show_header=True, header_style="bold white on blue", expand=True, title="[bold]COMMAND CENTER[/bold]")
        menu.add_column("ID", justify="center", style="bold yellow", width=4)
        menu.add_column("COMMAND", style="bold cyan")
        menu.add_column("DESCRIPTION", style="white")
        
        menu.add_row("1", "REFRESH", "Update dashboard metrics")
        menu.add_row("2", "CONNECT", "Configure RPC settings")
        menu.add_row("3", "WALLET", "Check balance")
        menu.add_row("4", "EXPLORER", "Lookup Block/TX")
        menu.add_row("5", "TRANSFER", "Send Funds")
        menu.add_row("0", "EXIT", "Quit Terminal")
        
        console.print(menu)
        
        choice = Prompt.ask("[bold on blue] SELECT ACTION [/bold on blue]", choices=["0","1","2","3","4","5"], default="1")
        
        if choice == "0":
            console.print("[yellow]Shutting down...[/yellow]")
            if app.sdk:
                await app.sdk.disconnect()
            sys.exit(0)
            
        elif choice == "1":
            continue # Loop refreshes
            
        elif choice == "2":
            rpc = Prompt.ask("[bold]RPC URL[/bold]", default="http://127.0.0.1:8545")
            ws = Prompt.ask("[bold]WS URL[/bold] (optional)", default="")
            cid = IntPrompt.ask("[bold]Chain ID[/bold]", 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")
            try:
                bal = await app.sdk.get_balance(addr)
                console.print(Panel(f"[bold green]{bal.balance} {bal.symbol}[/bold green]", title="Wallet Balance", expand=False))
            except Exception as e:
                 console.print(f"[red]Error fetching balance: {e}[/red]")
            Prompt.ask("Press Enter to continue")
            
        elif choice == "4":
             if not app.connected:
                console.print("[red]⚠ Not Connected[/red]")
                Prompt.ask("Press Enter")
                continue
             mode = Prompt.ask("Search by", choices=["block", "tx"], default="block")
             try:
                 if mode == "block":
                     num = IntPrompt.ask("Block Number")
                     blk = await app.sdk.get_block(num)
                     console.print(blk)
                 else:
                     h = Prompt.ask("Tx Hash")
                     tx = await app.sdk.get_transaction(h)
                     console.print(tx)
             except Exception as e:
                 console.print(f"[red]Error: {e}[/red]")
             Prompt.ask("Press Enter to continue")
             
        elif choice == "5":
             # Combined Send TX
             if not app.connected:
                console.print("[red]⚠ Not Connected[/red]")
                Prompt.ask("Press Enter")
                continue
             t = Prompt.ask("Recipient")
             v = Prompt.ask("Amount (wei)")
             pk = Prompt.ask("Private Key", password=True)
             try:
                 tx_hash = await app.sdk.send_transaction(Transaction("", t, v), pk)
                 console.print(Panel(f"[green]Transaction Sent![/green]\nHash: {tx_hash}", title="Success", border_style="green"))
             except Exception as e:
                 console.print(f"[red]Transaction Failed:[/red] {e}")
             Prompt.ask("Press Enter to continue")


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

if __name__ == "__main__":
    main()

