import os
import sys
import warnings
import re
from datetime import datetime
import platform
import json

warnings.filterwarnings("ignore")

os.environ["ALSA_CONF_PATH"] = "/dev/null"
os.environ["PYAudio"] = "0"

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from dotenv import load_dotenv
from ana_assistant.core.llm import LLM
from ana_assistant.core.browser import Browser
from ana_assistant.core.desktop import Desktop
from ana_assistant.core.system_control import SystemControl
from ana_assistant.core.ui import (
    banner,
    info,
    success,
    warning,
    error,
    ana_speak,
    user_input,
    UI,
    console,
)
from ana_assistant.memory.storage import Memory
from ana_assistant.skills.scraper import WebScraper
from ana_assistant.skills.system import SystemCommands
from ana_assistant.skills.email import Email
from ana_assistant.skills.messenger import Messenger
from ana_assistant.skills.filesystem import FileSystem

load_dotenv()


class Ana:
    def __init__(self):
        self.llm = LLM(provider="groq")
        self.browser = None
        self.desktop = Desktop()
        self.sys = SystemControl()
        self.memory = Memory()
        self.commands = SystemCommands()
        self.scraper = WebScraper()
        self.email = Email()
        self.messenger = Messenger()
        self.fs = FileSystem()
        self.start_time = datetime.now()

    def start(self):
        os.system("clear")
        console.print(banner())
        info("Initializing Ana...")
        info(f"System: {platform.system()} | Uptime: {self._get_uptime()}")
        print()
        success("Ana is ready!")
        print()

        ana_speak("Hello, I am Ana. Your system is ready. How can I help you?")
        print()

        while True:
            try:
                text = user_input()
                if text:
                    self.process(text)
            except (EOFError, KeyboardInterrupt):
                self._shutdown()

    def process(self, text):
        self.memory.add("user", text)
        command = text.lower()

        if any(word in command for word in ["bye", "exit", "quit", "goodbye"]):
            self._shutdown()

        info(f"You: {text}")
        response = self.handle_command(command, text)
        ana_speak(response)
        print()
        self.memory.add("assistant", response)

    def tool_callback(self, tool_name, args):
        """Execute tools based on name"""
        if tool_name == "get_system_info":
            return json.dumps(self.sys.get_system_info())
        elif tool_name == "get_cpu_usage":
            return json.dumps(self.sys.get_cpu_info())
        elif tool_name == "get_memory_usage":
            return json.dumps(self.sys.get_memory_info())
        elif tool_name == "get_disk_usage":
            return json.dumps(self.sys.get_disk_info())
        elif tool_name == "get_battery_status":
            return json.dumps(self.sys.get_battery_info())
        elif tool_name == "get_network_status":
            return json.dumps(self.sys.get_network_info())
        elif tool_name == "get_running_processes":
            return json.dumps(self.sys.get_processes(args.get("limit", 10)))
        elif tool_name == "take_screenshot":
            return self.sys.take_screenshot()
        elif tool_name == "open_application":
            return self.sys.open_app(args.get("app_name", ""))
        elif tool_name == "shutdown_computer":
            return self.sys.shutdown()
        elif tool_name == "restart_computer":
            return self.sys.restart()
        elif tool_name == "lock_screen":
            return self.sys.lock_screen()
        elif tool_name == "scrape_website":
            url = args.get("url", "")
            selector = args.get("selector", "")
            if selector:
                html = self.scraper.fetch(url)
                return self.scraper.get_text(html, selector)
            return self.scraper.fetch(url)[:500]
        elif tool_name == "browser_open":
            if not self.browser:
                self.browser = Browser()
            self.browser.open(args.get("url", ""))
            return f"Opened {args.get('url', '')}"
        elif tool_name == "desktop_click":
            x, y = args.get("x", 0), args.get("y", 0)
            self.desktop.click(x, y)
            return f"Clicked at ({x}, {y})"
        elif tool_name == "desktop_type":
            return self.desktop.type(args.get("text", ""))
        elif tool_name == "list_directory":
            return self._list_directory(
                args.get("path", "."), args.get("show_hidden", False)
            )
        elif tool_name == "read_file":
            return self._read_file(args.get("path", ""), args.get("max_lines", 100))
        elif tool_name == "write_file":
            return self._write_file(args.get("path", ""), args.get("content", ""))
        elif tool_name == "create_folder":
            return self._create_folder(args.get("path", ""))
        elif tool_name == "delete_file":
            return self._delete_file(args.get("path", ""))
        elif tool_name == "delete_folder":
            return self._delete_folder(args.get("path", ""))
        elif tool_name == "get_file_info":
            return self._get_file_info(args.get("path", ""))
        elif tool_name == "get_home_directory":
            return os.path.expanduser("~")
        elif tool_name == "get_current_directory":
            return os.getcwd()
        elif tool_name == "change_directory":
            try:
                os.chdir(args.get("path", "~"))
                return f"Changed directory to {os.getcwd()}"
            except Exception as e:
                return f"Failed to change directory: {str(e)}"
        elif tool_name == "search_files":
            return self._search_files(
                args.get("directory", "."), args.get("pattern", "*")
            )
        elif tool_name == "execute_command":
            return self._execute_command(args.get("command", ""))
        elif tool_name == "copy_file":
            return self._copy_file(args.get("source", ""), args.get("destination", ""))
        elif tool_name == "move_file":
            return self._move_file(args.get("source", ""), args.get("destination", ""))
        elif tool_name == "run_python":
            return self._run_python(args.get("code", ""))
        elif tool_name == "append_file":
            return self._append_file(args.get("path", ""), args.get("content", ""))
        else:
            return f"Unknown tool: {tool_name}"

    def handle_command(self, command, original_text):
        try:
            if any(
                k in command
                for k in ["system info", "system information", "about my pc"]
            ):
                return self._format_system_info()

            elif "cpu" in command and any(
                k in command for k in ["usage", "info", "processor"]
            ):
                return self._format_cpu()

            elif any(k in command for k in ["memory", "ram", "how much ram"]):
                return self._format_memory()

            elif any(k in command for k in ["disk", "storage", "hard drive", "space"]):
                return self._format_disk()

            elif any(k in command for k in ["battery", "charge", "power"]):
                return self._format_battery()

            elif any(k in command for k in ["network", "internet", "connection"]):
                return self._format_network()

            elif any(k in command for k in ["processes", "running apps", "tasks"]):
                return self._format_processes()

            elif any(
                k in command for k in ["screenshot", "capture screen", "screen shot"]
            ):
                return self.sys.take_screenshot()

            elif "shutdown" in command:
                return self.sys.shutdown()

            elif "restart" in command:
                return self.sys.restart()

            elif "sleep" in command:
                return self.sys.sleep()

            elif "lock" in command and "screen" in command:
                return self.sys.lock_screen()

            elif "open" in command:
                app = re.search(r"open\s+(.+)", command)
                if app:
                    return self.sys.open_app(app.group(1).strip())

            elif "send email" in command or "send mail" in command:
                return self._handle_email(command, original_text)

            elif "send message" in command or "message" in command:
                return self._handle_messaging(command, original_text)

            elif "help" in command:
                return self._show_help()

            else:
                # info("Thinking...")

                # Build comprehensive system prompt with available tools
                tool_descriptions = """
IMPORTANT: You MUST use the available tools to answer questions. DO NOT write code or explain what you would do. Actually call the tools!

AVAILABLE TOOLS:
- get_system_info: Get OS, architecture, hostname
- get_cpu_usage: Get CPU percentage and cores
- get_memory_usage: Get RAM usage
- get_disk_usage: Get disk space
- get_battery_status: Get battery info
- get_network_status: Get network stats
- get_running_processes: List running processes
- take_screenshot: Capture screen
- open_application: Open apps/URLs
- shutdown_computer: Turn off PC
- restart_computer: Reboot PC
- lock_screen: Lock PC
- scrape_website: Get content from URLs
- browser_open: Open URLs in browser
- desktop_click: Click at coordinates
- desktop_type: Type text
- list_directory: List files/folders in a directory (use: {"path": "."})
- read_file: Read content of a file (use: {"path": "/path/to/file"})
- write_file: Write content to a file
- create_folder: Create a new directory
- delete_file: Delete a file
- delete_folder: Delete an empty directory
- get_file_info: Get file/folder info (size, date)
- get_home_directory: Get user's home folder
- get_current_directory: Get current directory
- change_directory: Change current directory
- search_files: Search for files by pattern
- execute_command: Run shell commands (ls, cat, mkdir, etc.)
- copy_file: Copy files from source to destination
- move_file: Move files from source to destination
- run_python: Execute Python code and get output
- append_file: Append content to a file

IMPORTANT INSTRUCTIONS:
1. When user asks to see files, folders, or filesystem -> call list_directory
2. When user asks about system info -> call appropriate tool
3. When user asks about files -> call read_file
4. When user asks to create/write/edit code -> call write_file
5. When user asks to run Python code -> call run_python
6. When user asks to run terminal commands -> call execute_command
7. ALWAYS use tools, NEVER write example code!
8. Works on Linux, macOS, and Windows!
"""
                system_prompt = (
                    "You are Ana, an advanced AI assistant. " + tool_descriptions
                )

                return self.llm.ask_with_tools(
                    original_text,
                    system_prompt,
                    self.llm.TOOLS,
                    self.tool_callback,
                )

        except Exception as e:
            return f"I encountered an error: {str(e)}"

    def _format_system_info(self):
        info_data = self.sys.get_system_info()
        return f"""
╭─ System Information ───────────────────────╮
│ Platform:  {info_data["platform"]}
│ Release:   {info_data["platform_release"]}
│ Machine:   {info_data["architecture"]}
│ Hostname:  {info_data["hostname"]}
╰────────────────────────────────────────────╯"""

    def _format_cpu(self):
        info_data = self.sys.get_cpu_info()
        bar = self._make_bar(info_data["cpu_percent"])
        return f"CPU {bar} {info_data['cpu_percent']}% | {info_data['cpu_count_physical']} cores"

    def _format_memory(self):
        info_data = self.sys.get_memory_info()
        bar = self._make_bar(info_data["percent"])
        return f"RAM {bar} {info_data['used']}GB / {info_data['total']}GB ({info_data['percent']}%)"

    def _format_disk(self):
        info_data = self.sys.get_disk_info()
        result = []
        for part in info_data:
            bar = self._make_bar(part["percent"])
            result.append(
                f"{part['mountpoint']} {bar} {part['used']}GB / {part['total']}GB"
            )
        return "\n".join(result)

    def _format_battery(self):
        info_data = self.sys.get_battery_info()
        if "error" not in info_data:
            bar = self._make_bar(info_data["percent"])
            status = "Plugged" if info_data["plugged_in"] else "Unplugged"
            return f"Battery {bar} {info_data['percent']}% ({status})"
        return "No battery detected"

    def _format_network(self):
        info_data = self.sys.get_network_info()
        return f"Network: Up {info_data['bytes_sent']}MB | Down {info_data['bytes_recv']}MB"

    def _format_processes(self):
        procs = self.sys.get_processes(5)
        items = "\n  ".join(
            [f"{p['name']} ({p['cpu_percent']}%)" for p in procs if p["name"]]
        )
        return f"Top Processes:\n  {items}"

    def _make_bar(self, percent, width=10):
        filled = int(width * percent / 100)
        bar = "=" * filled + "-" * (width - filled)
        if percent < 30:
            color = UI.GREEN
        elif percent < 70:
            color = UI.YELLOW
        else:
            color = UI.RED
        return f"[{color}]{bar}[/{color}]"

    def _show_help(self):
        return f"""
╭─ Ana Commands ──────────────────────────────╮
│ System: system info, cpu, memory, disk
│ Power:  shutdown, restart, sleep, lock
│ Apps:   open [app], screenshot
│ Email:  send email to [address]
│ Chat:   send message on whatsapp/telegram
│ Web:    scrape website, open browser
│ Help:   show this help
╰────────────────────────────────────────────╯"""

    def _handle_email(self, command, original_text):
        to_match = re.search(r"(?:to|for)\s+([^\s]+@[^\s]+)", command)
        if to_match:
            to_email = to_match.group(1)
            subject_match = re.search(r"subject[:\s]+(.+?)(?:\s|$)", command)
            subject = subject_match.group(1) if subject_match else "Message from Ana"
            return self.email.send(to_email, subject, original_text)
        return "Please specify email: send email to address"

    def _handle_messaging(self, command, original_text):
        if "whatsapp" in command:
            phone_match = re.search(r"(?:to|number)\s*(\+?[\d]+)", command)
            if phone_match:
                return self.messenger.send_whatsapp(phone_match.group(1), original_text)
            return "Specify: send message on whatsapp to +123456"

        elif "telegram" in command:
            chat_match = re.search(r"(?:to|chat)\s*([^\s]+)", command)
            if chat_match:
                return self.messenger.send_telegram(chat_match.group(1), original_text)
            return "Specify: send message on telegram to chat_id"

        elif "discord" in command:
            return self.messenger.send_discord(
                os.getenv("DISCORD_WEBHOOK_URL"), original_text
            )

        elif "slack" in command:
            return self.messenger.send_slack("general", original_text)

        return "Platform: whatsapp, telegram, discord, slack"

    def _list_directory(self, path=".", show_hidden=False):
        try:
            entries = os.listdir(path)
            if not show_hidden:
                entries = [e for e in entries if not e.startswith(".")]
            entries.sort()
            result = []
            for entry in entries:
                full_path = os.path.join(path, entry)
                if os.path.isdir(full_path):
                    result.append(f"[DIR]  {entry}/")
                else:
                    size = os.path.getsize(full_path)
                    result.append(f"[FILE] {entry} ({size} bytes)")
            return "\n".join(result) if result else "Empty directory"
        except Exception as e:
            return f"Error listing directory: {str(e)}"

    def _read_file(self, path, max_lines=100):
        try:
            with open(path, "r", encoding="utf-8") as f:
                lines = f.readlines()[:max_lines]
            content = "".join(lines)
            if len(content) > 5000:
                content = content[:5000] + "\n... (truncated)"
            return content
        except Exception as e:
            return f"Error reading file: {str(e)}"

    def _write_file(self, path, content):
        try:
            os.makedirs(os.path.dirname(path), exist_ok=True)
            with open(path, "w", encoding="utf-8") as f:
                f.write(content)
            return f"File written successfully: {path}"
        except Exception as e:
            return f"Error writing file: {str(e)}"

    def _create_folder(self, path):
        try:
            os.makedirs(path, exist_ok=True)
            return f"Folder created: {path}"
        except Exception as e:
            return f"Error creating folder: {str(e)}"

    def _delete_file(self, path):
        try:
            os.remove(path)
            return f"File deleted: {path}"
        except Exception as e:
            return f"Error deleting file: {str(e)}"

    def _delete_folder(self, path):
        try:
            os.rmdir(path)
            return f"Folder deleted: {path}"
        except Exception as e:
            return f"Error deleting folder: {str(e)}"

    def _get_file_info(self, path):
        try:
            stat = os.stat(path)
            info = {
                "path": path,
                "type": "directory" if os.path.isdir(path) else "file",
                "size": stat.st_size,
                "modified": datetime.fromtimestamp(stat.st_mtime).strftime(
                    "%Y-%m-%d %H:%M:%S"
                ),
            }
            return json.dumps(info, indent=2)
        except Exception as e:
            return f"Error getting file info: {str(e)}"

    def _search_files(self, directory, pattern):
        try:
            import glob

            results = glob.glob(os.path.join(directory, pattern))
            if not results:
                return f"No files matching '{pattern}' found in {directory}"
            return "\n".join(results)
        except Exception as e:
            return f"Error searching files: {str(e)}"

    def _execute_command(self, command):
        try:
            import subprocess

            result = subprocess.run(
                command, shell=True, capture_output=True, text=True, timeout=30
            )
            output = result.stdout if result.stdout else result.stderr
            if not output:
                output = "Command executed successfully (no output)"
            return output[:2000]
        except Exception as e:
            return f"Error executing command: {str(e)}"

    def _copy_file(self, source, destination):
        try:
            import shutil

            shutil.copy2(source, destination)
            return f"Copied {source} to {destination}"
        except Exception as e:
            return f"Error copying file: {str(e)}"

    def _move_file(self, source, destination):
        try:
            import shutil

            shutil.move(source, destination)
            return f"Moved {source} to {destination}"
        except Exception as e:
            return f"Error moving file: {str(e)}"

    def _run_python(self, code):
        try:
            import io
            import contextlib

            output = io.StringIO()
            with contextlib.redirect_stdout(output):
                exec(code)
            result = output.getvalue()
            return result if result else "Code executed successfully (no output)"
        except Exception as e:
            return f"Error: {str(e)}"

    def _append_file(self, path, content):
        try:
            os.makedirs(os.path.dirname(path), exist_ok=True)
            with open(path, "a", encoding="utf-8") as f:
                f.write(content)
            return f"Content appended to {path}"
        except Exception as e:
            return f"Error appending to file: {str(e)}"

    def _get_uptime(self):
        delta = datetime.now() - self.start_time
        return str(delta).split(".")[0]

    def _shutdown(self):
        success("Goodbye!")
        sys.exit()


if __name__ == "__main__":
    if "--classic" in sys.argv:
        ana = Ana()
        ana.start()
    else:
        try:
            from tui_app import AnaTUI

            app = AnaTUI()
            app.run()
        except ImportError:
            ana = Ana()
            ana.start()
