import os
import sys
import json
import re
from textual.app import App, ComposeResult
from textual.widgets import (
    Header,
    Footer,
    Input,
    RichLog,
    Static,
    Button,
    Select,
    Label,
    ListView,
    ListItem,
)
from textual.containers import Horizontal, Vertical, VerticalScroll
from textual.screen import Screen
from textual import work, on
from ana_assistant.ana import Ana
from ana_assistant.skills.cybersecurity import CyberTools


HACKER_SYSTEM_PROMPT = """You are Ana CyberSec, an elite cybersecurity expert and ethical hacker. You think and act like a real hacker.

Your capabilities:
- Network penetration testing and analysis
- Vulnerability assessment
- Security auditing
- CTF challenge solving
- Reverse engineering concepts
- Malware analysis fundamentals
- Digital forensics awareness
- Web application security testing

You have access to cybersecurity tools:
- Port scanning, DNS lookups, WHOIS
- SSL/TLS analysis
- Hash identification and encoding/decoding (base64, hex, URL)
- Geolocation and MAC lookup
- Network reconnaissance

Your personality:
- Speak like an elite hacker
- Use technical jargon appropriately
- Think in attack vectors and defense strategies
- Be precise and technical
- Show real cybersecurity knowledge
- Explain techniques and countermeasures

When analyzing:
- Think like an attacker: reconnaissance, weaponization, exploitation, actions on objectives
- Consider OWASP Top 10, MITRE ATT&CK framework concepts
- Reference real CVEs and vulnerabilities when relevant
- Explain the "why" behind security issues

Always be ethical - emphasize responsible disclosure and authorized testing only."""


class CyberSecScreen(Screen):
    def __init__(self):
        super().__init__()
        self.cyber = CyberTools()
        self.llm = None

    def compose(self) -> ComposeResult:
        yield Header(show_clock=True)
        yield Label(
            "[bold red]── CYBERSECURITY COMMAND CENTER ──[/bold red]", id="cyber_title"
        )
        yield RichLog(id="cyber_log", wrap=True, markup=True)
        yield Input(
            placeholder="Enter command or ask CyberSec AI... (type 'help' for tools)",
            id="cyber_input",
        )
        yield Button("Back to Chat", id="btn_back_cyber", variant="error")
        yield Footer()

    def on_mount(self) -> None:
        self._init_llm()
        log = self.query_one("#cyber_log", RichLog)

        banner = """
[bold red]╔═══════════════════════════════════════════════════════════╗[/bold red]
[bold red]║[/bold red]     [bold white on red]ANA CYBERSEC COMMAND CENTER[/bold white on red]                    [bold red]║[/bold red]
[bold red]╚═══════════════════════════════════════════════════════════╝[/bold red]

[green]>>[/green] CyberSec AI initialized
[green]>>[/green] Hacker mode: ACTIVE
[green]>>[/green] Type 'help' for available commands or ask me anything!

"""
        log.write(banner)

    def _init_llm(self):
        try:
            from ana_assistant.core.llm import LLM

            self.llm = LLM(provider="groq")
        except Exception as e:
            self.llm = None

    @work(thread=True)
    async def _process_input(self, user_input: str) -> None:
        log = self.query_one("#cyber_log", RichLog)

        if not user_input.strip():
            return

        # Show user input
        self.app.call_from_thread(log.write, f"\n[cyan]┌─ User[/cyan]")
        self.app.call_from_thread(log.write, f"[cyan]└─ >[/cyan] {user_input}\n")

        cmd_lower = user_input.lower().strip()

        # Check for tool commands first
        if self._is_tool_command(cmd_lower):
            result = self._execute_tool(cmd_lower, user_input)
            self.app.call_from_thread(log.write, f"[yellow]┌─ Tool Output[/yellow]")
            self.app.call_from_thread(log.write, f"[yellow]└─ >[/yellow]\n{result}\n")
        elif cmd_lower in ["help", "tools", "commands"]:
            self._show_help()
        elif cmd_lower in ["exit", "back", "quit"]:
            self.app.call_from_thread(self.app.pop_screen)
        elif cmd_lower in ["net", "network"]:
            self._show_network()
        elif cmd_lower in ["myip", "publicip", "ip"]:
            self._show_myip()
        elif cmd_lower == "localip":
            self._show_localip()
        else:
            # Use AI for everything else
            await self._ask_ai(user_input)

    def _is_tool_command(self, cmd: str) -> bool:
        tool_cmds = [
            "scan",
            "ping",
            "dns",
            "reverse",
            "checkdns",
            "subnet",
            "headers",
            "ssl",
            "whois",
            "hash",
            "base64",
            "hex",
            "url",
            "geoip",
            "mac",
            "wifi",
            "bluetooth",
            "phone",
            "device",
            "traceroute",
            "arp",
            "subdomain",
            "vulners",
            "system",
            "quick",
            "xss",
            "sql",
            "html",
            "strength",
            "myip",
            "localip",
        ]
        return any(cmd.startswith(c) for c in tool_cmds)

    def _execute_tool(self, cmd_lower: str, full_cmd: str) -> str:
        parts = full_cmd.split(maxsplit=2)
        cmd = parts[0].lower()
        arg1 = parts[1] if len(parts) > 1 else ""
        arg2 = parts[2] if len(parts) > 2 else ""

        tools_map = {
            "scan": lambda: self.cyber.port_scan(arg1 or "localhost", arg2 or "1-1000"),
            "quick": lambda: self.cyber.quick_scan(arg1 or "localhost"),
            "fullscan": lambda: self.cyber.full_port_scan(arg1 or "localhost"),
            "ping": lambda: self.cyber.ping_host(arg1),
            "traceroute": lambda: self.cyber.traceroute(arg1),
            "arp": lambda: self.cyber.arp_scan(),
            "dns": lambda: self.cyber.dns_lookup(arg1),
            "reverse": lambda: self.cyber.reverse_dns(arg1),
            "checkdns": lambda: self.cyber.check_dns(arg1),
            "subdomain": lambda: self.cyber.subdomain_enum(arg1),
            "subnet": lambda: self.cyber.subnet_calc(arg1),
            "headers": lambda: self.cyber.http_headers(arg1),
            "http": lambda: self.cyber.http_scan(arg1),
            "website": lambda: self.cyber.website_scan(arg1),
            "ssl": lambda: self.cyber.ssl_check(arg1),
            "whois": lambda: self.cyber.whois_lookup(arg1),
            "hash": lambda: self.cyber.hash_identify(arg1),
            "strength": lambda: self.cyber.password_strength(arg1),
            "base64": lambda: self.cyber.base64_encode(arg1),
            "base64d": lambda: self.cyber.base64_decode(arg1),
            "hex": lambda: self.cyber.hex_encode(arg1),
            "hexd": lambda: self.cyber.hex_decode(arg1),
            "url": lambda: self.cyber.url_encode(arg1),
            "urld": lambda: self.cyber.url_decode(arg1),
            "html": lambda: self.cyber.html_encode(arg1),
            "htmld": lambda: self.cyber.html_decode(arg1),
            "geoip": lambda: self.cyber.geoip_lookup(arg1),
            "mac": lambda: self.cyber.mac_lookup(arg1),
            "wifi": lambda: self.cyber.wifi_scan(),
            "bluetooth": lambda: self.cyber.bluetooth_scan(),
            "phone": lambda: self.cyber.phone_info(arg1),
            "device": lambda: self.cyber.device_scan(arg1 or "192.168.1.0/24"),
            "sql": lambda: self.cyber.sql_injection_test(arg1),
            "xss": lambda: self.cyber.xss_test(arg1),
            "vulners": lambda: self.cyber.vulners_scan(arg1),
            "system": lambda: self.cyber.system_info(),
            "myip": lambda: self.cyber.get_public_ip(),
            "localip": lambda: (
                f"Local: {self.cyber.get_local_ip()}\nMAC: {self.cyber.get_mac_address()}\nInterfaces:\n{self.cyber.get_all_interfaces()}"
            ),
        }

        if cmd in tools_map:
            try:
                return tools_map[cmd]()
            except Exception as e:
                return f"[red]Error:[/red] {str(e)}"
        return f"[red]Unknown command:[/red] {cmd}"

    def _show_help(self):
        log = self.query_one("#cyber_log", RichLog)
        help_text = """
[cyan]╔═══════════════════════════════════════════════════════════════╗[/cyan]
[cyan]║[/cyan]              [bold]AVAILABLE CYBERSECURITY TOOLS[/bold]              [cyan]║[/cyan]
[cyan]╚═══════════════════════════════════════════════════════════════╝[/cyan]

[yellow]Network Reconnaissance:[/yellow]
  scan <host> <ports>   - Port scan (e.g., scan 192.168.1.1 1-1000)
  ping <host>            - Ping sweep
  dns <domain>           - DNS enumeration
  reverse <ip>          - Reverse DNS lookup
  checkdns <domain>      - DNS record checker (A, MX, NS, TXT)

[yellow]Web Application Testing:[/yellow]
  headers <url>         - HTTP headers analysis
  ssl <host>            - SSL/TLS certificate audit
  whois <domain>        - WHOIS reconnaissance

[yellow]Cryptography & Encoding:[/yellow]
  hash <string>         - Hash identification (MD5, SHA1, etc.)
  base64 <text>         - Base64 encode
  base64d <text>        - Base64 decode
  hex <text>            - Hexadecimal encode
  hexd <hex>            - Hexadecimal decode
  url <text>            - URL encode
  urld <text>           - URL decode

[yellow]Intelligence Gathering:[/yellow]
  geoip <ip>            - IP geolocation lookup
  mac <address>         - MAC vendor identification
  myip                  - Get your public IP
  localip               - Get local IP address
  net                   - Full network status

[yellow]AI Mode:[/yellow]
  Ask any cybersecurity question in plain English!
  Example: "How do I perform SQL injection testing?"
  Example: "Explain the stages of a cyber attack"

[yellow]System:[/yellow]
  help                  - Show this menu
  exit                  - Return to main chat
"""
        log.write(help_text)

    def _show_network(self):
        log = self.query_one("#cyber_log", RichLog)
        inet = self.cyber.check_internet()
        local = self.cyber.get_local_ip()
        public = self.cyber.get_public_ip()

        status = f"""
[cyan]╔═════════════════════════════════════╗[/cyan]
[cyan]║[/cyan]         [bold]NETWORK STATUS[/bold]                [cyan]║[/cyan]
[cyan]╠═════════════════════════════════════╣[/cyan]
[cyan]║[/cyan] Internet:  {"[green]CONNECTED[/green]" if inet == "Connected" else "[red]DISCONNECTED[/red]"}          [cyan]║[/cyan]
[cyan]║[/cyan] Local IP:   {local:<27}[cyan]║[/cyan]
[cyan]║[/cyan] Public IP:  {public:<27}[cyan]║[/cyan]
[cyan]╚═════════════════════════════════════╝[/cyan]
"""
        log.write(status)

    def _show_myip(self):
        log = self.query_one("#cyber_log", RichLog)
        ip = self.cyber.get_public_ip()
        geo = self.cyber.geoip_lookup(ip)
        log.write(f"\n[green]>>[/green] Your Public IP: {ip}")
        log.write(f"[green]>>[/green] Geolocation:\n{geo}\n")

    def _show_localip(self):
        log = self.query_one("#cyber_log", RichLog)
        ip = self.cyber.get_local_ip()
        log.write(f"\n[green]>>[/green] Local IP: {ip}\n")

    async def _ask_ai(self, question: str):
        log = self.query_one("#cyber_log", RichLog)

        if not self.llm:
            log.write("[red]AI not available. Using tool mode only.[/red]")
            return

        self.app.call_from_thread(
            log.write, "\n[italic dim]>> CyberSec AI analyzing...[/italic dim]"
        )

        try:
            response = self.llm.ask(question, HACKER_SYSTEM_PROMPT)
            self.app.call_from_thread(log.write, f"\n[red]┌─ Ana CyberSec[/red]")
            self.app.call_from_thread(log.write, f"[red]└─ >[/red]\n{response}\n")
        except Exception as e:
            self.app.call_from_thread(log.write, f"\n[red]AI Error: {str(e)}[/red]\n")

    @on(Input.Submitted, "#cyber_input")
    def on_cyber_input(self, event: Input.Submitted) -> None:
        user_input = event.value.strip()
        event.input.value = ""
        self._process_input(user_input)

    @on(Button.Pressed, "#btn_back_cyber")
    def go_back(self) -> None:
        self.app.pop_screen()


class GamesScreen(Screen):
    def compose(self) -> ComposeResult:
        yield Header(show_clock=True)
        yield Label(
            "[bold magenta]── ANA GAMES PORTAL ──[/bold magenta]", id="games_title"
        )
        yield ListView(
            ListItem(Label("Tic-Tac-Toe"), id="game_ttt"),
            ListItem(Label("Snake"), id="game_snake"),
            ListItem(Label("Trivia"), id="game_trivia"),
            ListItem(Label("Number Guesser"), id="game_number"),
            ListItem(Label("Doge Runner"), id="game_doge"),
            id="games_list",
        )
        yield Button("Back to Chat", id="btn_back_games", variant="error")
        yield Footer()

    @on(Button.Pressed, "#btn_back_games")
    def go_back(self) -> None:
        self.app.pop_screen()

    @on(ListView.Selected, "#games_list")
    def on_game_selected(self, event: ListView.Selected):
        game_id = event.item.id
        from ana_assistant.games import (
            TicTacToeScreen,
            NumberGuesserScreen,
            TriviaScreen,
            SnakeScreen,
            DogeRunnerScreen,
        )

        if game_id == "game_ttt":
            self.app.push_screen(TicTacToeScreen())
        elif game_id == "game_snake":
            self.app.push_screen(SnakeScreen())
        elif game_id == "game_trivia":
            self.app.push_screen(TriviaScreen())
        elif game_id == "game_number":
            self.app.push_screen(NumberGuesserScreen())
        elif game_id == "game_doge":
            self.app.push_screen(DogeRunnerScreen())
        else:
            self.app.notify("Coming soon!", title="Games Portal")


class AnaTUI(App):
    CSS = """
    #main_pane {
        width: 3fr;
    }
    #sidebar {
        width: 1fr;
        border-left: solid cyan;
        padding: 1 2;
        background: #0d1117;
    }
    RichLog {
        height: 1fr;
        border: solid cyan;
        background: #0d1117;
    }
    #cyber_log {
        height: 1fr;
        border: solid red;
        background: #0d1117;
    }
    Input {
        dock: bottom;
    }
    Button {
        width: 100%;
        margin-top: 1;
    }
    Select {
        width: 100%;
        margin-top: 1;
    }
    .section_heading {
        margin-top: 1;
        text-align: center;
    }
    #cyber_title {
        content-align: center middle;
        width: 100%;
        padding: 2 0;
        background: #0d1117;
    }
    #games_title {
        content-align: center middle;
        width: 100%;
        padding: 2 0;
        background: #0d1117;
    }
    #games_list {
        margin: 2 10;
        height: 1fr;
    }
    """

    def __init__(self):
        super().__init__()
        self.ana = Ana()
        self.cyber_mode = False

    def compose(self) -> ComposeResult:
        yield Header(show_clock=True, id="header")
        with Horizontal():
            with Vertical(id="main_pane"):
                yield RichLog(id="chat_log", wrap=True, markup=True)
                yield Input(
                    placeholder="Type a message to Ana... (type 'exit' to quit)",
                    id="input_box",
                )
            with VerticalScroll(id="sidebar"):
                yield Static(id="dashboard_stats")

                yield Static(
                    "[bold cyan]── FEATURES ──[/bold cyan]", classes="section_heading"
                )
                yield Button("🎤 Voice Options", id="btn_voice", variant="primary")
                yield Button("🔒 CyberSec Tools", id="btn_cybersec", variant="error")
                yield Button("🎮 Play Games", id="btn_games", variant="success")

                yield Static(
                    "[bold cyan]── HISTORY ──[/bold cyan]", classes="section_heading"
                )
                yield Select([], prompt="Previous Chats...", id="history_select")
        yield Footer()

    def on_mount(self) -> None:
        self.title = "Ana AI Assistant"
        self.sub_title = "By DTC (Textual UI)"
        log = self.query_one(RichLog)

        from ana_assistant.core.ui import banner

        b = banner()
        log.write(b)

        internet = self.ana.sys.get_internet_connectivity()
        bt = self.ana.sys.get_bluetooth_status()
        net_cfg = self.ana.sys.get_network_configs()
        batt = self.ana.sys.get_battery_info()

        inet_color = "green" if internet == "Connected" else "red"
        bt_color = "green" if bt == "Enabled" else "yellow"

        if "error" in batt:
            batt_str = "[dim]No battery detected[/dim]"
        else:
            pct = batt.get("percent", 0)
            plugged = batt.get("plugged_in", False)
            if plugged:
                life = "Plugged In"
            else:
                hrs = batt.get("time_left", 0)
                if hrs and isinstance(hrs, (int, float)) and hrs > 0:
                    hrs = round(hrs / 60, 1)
                    life = f"{hrs} hrs left"
                else:
                    life = "Calculating..."
            charge_icon = "🔌" if plugged else "🔋"
            batt_str = f"{pct}% {charge_icon} ({life})"

        stats_markup = f"""[bold cyan]── SYSTEM STATUS ──[/bold cyan]

Platform: [green]{self.ana.sys.get_system_info()["platform"]}[/green]
CPU: [yellow]{self.ana.sys.get_cpu_info()["cpu_percent"]}%[/yellow]
Battery: [yellow]{batt_str}[/yellow]
Internet: [{inet_color}]{internet}[/{inet_color}]
Bluetooth: [{bt_color}]{bt}[/{bt_color}]

[bold cyan]── NETWORK CONF ──[/bold cyan]
"""
        for iface, ip in net_cfg.items():
            if iface != "lo":
                stats_markup += f"{iface}: [cyan]{ip}[/cyan]\n"

        self.query_one("#dashboard_stats", Static).update(stats_markup)

        self._update_history_dropdown()

        log.write(
            "\n[bold magenta]Ana:[/bold magenta] Hello, I am Ana. Your enhanced TUI is ready. How can I help you?"
        )
        log.write(
            "[dim italic]Hint: Hold SHIFT while dragging your mouse to select and copy text natively, or type 'copy' to copy my last response![/dim italic]\n"
        )

    @on(Button.Pressed, "#btn_cybersec")
    def handle_cybersec(self, event: Button.Pressed) -> None:
        self.push_screen(CyberSecScreen())

    @on(Button.Pressed, "#btn_voice")
    def handle_voice(self, event: Button.Pressed) -> None:
        self.query_one(RichLog).write(
            "\n[bold green]➜ Voice Interface initializing... (Feature coming soon!)[/bold green]"
        )

    @on(Button.Pressed, "#btn_games")
    def handle_games(self, event: Button.Pressed) -> None:
        self.push_screen(GamesScreen())

    @on(Select.Changed, "#history_select")
    def handle_history_select(self, event: Select.Changed) -> None:
        if event.value:
            timestamp = event.value
            history = self.ana.memory.load()
            log = self.query_one(RichLog)
            log.write(f"\n[bold cyan]── Historical Chat Record ──[/bold cyan]")

            for i, msg in enumerate(history):
                if msg.get("timestamp") == timestamp:
                    log.write(
                        f"[cyan]You ({msg.get('timestamp')[:16].replace('T', ' ')}):[/cyan] {msg.get('content')}"
                    )
                    if (
                        i + 1 < len(history)
                        and history[i + 1].get("role") == "assistant"
                    ):
                        log.write(
                            f"\n[bold magenta]Ana:[/bold magenta]\n{history[i + 1].get('content')}"
                        )
                    break
            # Clear the selection
            self.query_one("#history_select", Select).clear()

    async def on_input_submitted(self, message: Input.Submitted) -> None:
        user_input = message.value.strip()
        if not user_input:
            return

        inp = self.query_one(Input)
        inp.value = ""

        log = self.query_one(RichLog)
        log.write(f"[cyan]You:[/cyan] {user_input}")

        if user_input.lower() in ("exit", "quit", "bye", "clear", "copy"):
            if user_input.lower() == "clear":
                log.clear()
            elif user_input.lower() == "copy":
                if hasattr(self, "last_response") and self.last_response:
                    self.copy_to_clipboard(self.last_response)
                    log.write("[green]✔ Last response copied to clipboard![/green]")
                else:
                    log.write("[yellow]⚠ Nothing to copy yet.[/yellow]")
            else:
                self.exit()
            return

        self.process_command(user_input)

    @work(thread=True)
    def process_command(self, text: str) -> None:
        self.call_from_thread(self._write_thinking)

        self.ana.memory.add("user", text)
        try:
            response = self.ana.handle_command(text.lower(), text)
            self.ana.memory.add("assistant", response)
            self.last_response = response
            self.call_from_thread(self._update_history_dropdown)
            self.call_from_thread(self._write_response, response)
        except Exception as e:
            self.call_from_thread(self._write_response, f"[red]Error:[/red] {str(e)}")

    def _update_history_dropdown(self) -> None:
        history = self.ana.memory.load()
        options = []
        for msg in history:
            if msg.get("role") == "user":
                content = str(msg.get("content", ""))
                snippet = content[:25].replace("\n", " ")
                snippet += "..." if len(content) > 25 else ""

                time_str = msg.get("timestamp", "")
                if len(time_str) >= 16:
                    time_str = time_str[5:16].replace("T", " ")

                label = f"{time_str} | {snippet}"
                options.append((label, msg.get("timestamp", "")))

        if options:
            sel = self.query_one("#history_select", Select)
            sel.set_options(reversed(options[-50:]))

    def _write_thinking(self):
        log = self.query_one(RichLog)
        log.write("[italic dim]Ana is thinking...[/italic dim]")

    def _write_response(self, text: str):
        log = self.query_one(RichLog)
        log.write(f"[bold magenta]Ana:[/bold magenta]\n{text}\n")


def main():
    app = AnaTUI()
    app.run()

if __name__ == "__main__":
    main()
