"""
TaskingBot AI Desktop App — PyWebView-based native GUI.

Launches a native window with the TaskingBot chat UI and runs
the desktop agent poller in a background thread.
"""

import sys
import os
import platform
import base64
import json
import threading

# Ensure the agent package is importable when running standalone
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from .config import load_config, get_os_info, save_config, CONFIG_DIR
from .webui import DESKTOP_HTML


class DesktopAPI:
    """Python API exposed to the webview JS via window.pywebview.api."""

    def __init__(self, config, poller=None):
        self.config = config
        self.poller = poller
        self._window = None

    def set_window(self, window):
        self._window = window

    def toggle_fullscreen(self):
        """Toggle fullscreen mode."""
        if self._window:
            self._window.toggle_fullscreen()
            return {"success": True}
        return {"success": False}

    def minimize(self):
        """Minimize the window."""
        if self._window:
            self._window.minimize()
            return {"success": True}
        return {"success": False}

    def restore(self):
        """Restore window from minimized/fullscreen."""
        if self._window:
            self._window.restore()
            return {"success": True}
        return {"success": False}

    def resize_window(self, width=340, height=620):
        """Resize the window."""
        if self._window:
            self._window.resize(width, height)
            return {"success": True}
        return {"success": False}

    def get_os_info(self):
        """Return OS info dict for the Desktop panel."""
        return get_os_info()

    def take_screenshot(self):
        """Capture a screenshot and return as base64 PNG."""
        try:
            import mss
            from PIL import Image
            import io

            with mss.mss() as sct:
                # Capture the primary monitor
                monitor = sct.monitors[1]  # Primary monitor
                img = sct.grab(monitor)

                # Convert to PIL Image and then to base64
                pil_img = Image.frombytes("RGB", img.size, img.bgra, "raw", "BGRX")

                # Resize if very large (keep under 1920px wide for performance)
                max_w = 1920
                if pil_img.width > max_w:
                    ratio = max_w / pil_img.width
                    new_h = int(pil_img.height * ratio)
                    pil_img = pil_img.resize((max_w, new_h), Image.LANCZOS)

                buf = io.BytesIO()
                pil_img.save(buf, format="PNG", optimize=True)
                b64 = base64.b64encode(buf.getvalue()).decode("ascii")

                return {"ok": True, "data": b64}
        except Exception as e:
            return {"ok": False, "error": str(e)}

    def login(self, email, password):
        """Login via Python requests (bypasses CORS)."""
        import requests
        try:
            resp = requests.post(
                self.config.get("server_url", "https://tasking.tech") + "/_api/auth/login_with_password",
                json={"email": email, "password": password},
                timeout=15,
            )
            data = resp.json()
            if resp.ok:
                return {"ok": True, "token": data.get("token"), "user": data.get("user")}
            return {"ok": False, "error": data.get("message") or data.get("error") or "Login failed"}
        except Exception as e:
            return {"ok": False, "error": str(e)}

    def auto_login(self):
        """Auto-login using the configured desktop API key."""
        import requests
        api_key = self.config.get("api_key")
        if not api_key:
            return {"ok": False, "error": "No API key configured"}
        try:
            resp = requests.post(
                self.config.get("server_url", "https://tasking.tech") + "/_api/desktop/auth",
                headers={"Authorization": "Bearer " + api_key, "Content-Type": "application/json"},
                timeout=15,
            )
            data = resp.json()
            if resp.ok and data.get("token"):
                return {"ok": True, "token": data["token"], "user": data.get("user")}
            return {"ok": False, "error": data.get("error") or "Auth failed"}
        except Exception as e:
            return {"ok": False, "error": str(e)}

    def api_fetch(self, url, method="GET", body=None, token=None):
        """Proxy API requests through Python to bypass CORS."""
        import requests
        try:
            headers = {"Content-Type": "application/json"}
            if token:
                headers["Authorization"] = "Bearer " + token
            resp = requests.request(
                method, url, json=body if body else None,
                headers=headers, timeout=60,
            )
            return {"ok": resp.ok, "status": resp.status_code, "body": resp.text}
        except Exception as e:
            return {"ok": False, "error": str(e)}

    def chat_send(self, url, body, token):
        """Send chat message through Python (bypasses CORS). Returns full response."""
        import requests
        try:
            headers = {
                "Content-Type": "application/json",
                "Accept": "application/json",
            }
            if token:
                headers["Authorization"] = "Bearer " + token
            resp = requests.post(url, json=body, headers=headers, timeout=120)
            return {"ok": resp.ok, "status": resp.status_code, "body": resp.text}
        except Exception as e:
            return {"ok": False, "error": str(e)}

    def open_external(self, url):
        """Open a URL in the system's default browser."""
        import webbrowser
        webbrowser.open(url)
        return {"ok": True}

    def get_config(self):
        """Return the current config (without sensitive keys in full)."""
        cfg = dict(self.config)
        if cfg.get("api_key"):
            cfg["api_key"] = cfg["api_key"][:8] + "..."
        return cfg

    def get_agent_status(self):
        """Check if the poller is running."""
        if self.poller:
            return {"running": self.poller.running}
        return {"running": False}


def _start_poller_background(config, api_instance, window):
    """Start the desktop agent poller in a daemon thread."""
    from .poller import DesktopAgentPoller

    poller = DesktopAgentPoller(config)
    api_instance.poller = poller

    # Forward status messages to the webview
    def on_status(msg):
        if window:
            try:
                safe_msg = json.dumps(msg)
                window.evaluate_js(f"window.desktopAgentStatus({safe_msg})")
            except Exception:
                pass

    def on_action(action_type, result):
        if window:
            try:
                safe_msg = json.dumps(f"{action_type}: {'OK' if result.get('success') else 'FAILED'}")
                window.evaluate_js(f"window.desktopAgentStatus({safe_msg})")
            except Exception:
                pass

    poller.on_status = on_status
    poller.on_action = on_action

    # Send OS info to the webview once ready
    def send_os_info():
        import time
        time.sleep(2)  # Wait for webview to be ready
        if window:
            try:
                info = json.dumps(get_os_info())
                window.evaluate_js(f"window.desktopAgentOsInfo({info})")
            except Exception:
                pass

    threading.Thread(target=send_os_info, daemon=True).start()

    # Only start poller if API key is configured
    if config.get("api_key"):
        poller.run_in_background()
        # Auto-start LiveKit screen share in background
        threading.Thread(target=_start_screen_share, args=(config, on_status), daemon=True).start()
    else:
        on_status("Desktop agent not started — no API key configured. Use the Desktop tab or run 'tt-desktop setup'.")


def _start_screen_share(config, on_status):
    """Request a LiveKit token from the server and start screen sharing."""
    import time
    import asyncio
    import requests

    time.sleep(5)  # Wait for poller to connect first

    try:
        from .actions.screen_share import start_screen_share, is_sharing
    except ImportError:
        on_status("Screen share unavailable — livekit not installed")
        return

    if is_sharing():
        return

    server_url = config.get("server_url", "https://tasking.tech")
    api_key = config.get("api_key", "")
    agent_id = config.get("agent_id", "unknown")

    # Request LiveKit token from server
    try:
        res = requests.post(
            f"{server_url}/_api/livekit/token",
            headers={
                "Content-Type": "application/json",
                "Authorization": f"Bearer {api_key}",
            },
            json={
                "roomName": f"desktop-share-{agent_id[:8]}",
                "participantIdentity": f"desktop-{agent_id}",
                "participantName": "Desktop Agent Screen Share",
            },
            timeout=10,
        )
        if res.status_code != 200:
            on_status(f"Screen share: failed to get token ({res.status_code})")
            return

        # Try both superjson and plain JSON parsing
        data = None
        try:
            import superjson
            data = superjson.loads(res.text)
        except Exception:
            data = res.json()

        token = data.get("token") or (data.get("json", {}) or {}).get("token")
        livekit_url = data.get("url") or (data.get("json", {}) or {}).get("url")

        if not token or not livekit_url:
            on_status("Screen share: missing token/url from server")
            return

        on_status("Starting screen share...")

        # Run async screen share in new event loop
        loop = asyncio.new_event_loop()
        result = loop.run_until_complete(start_screen_share(livekit_url, token))
        if result:
            on_status("Screen share active ✅")
        else:
            on_status("Screen share failed to start")
    except Exception as e:
        on_status(f"Screen share error: {e}")


def launch_app(config=None):
    """Launch the TaskingBot AI desktop application."""
    try:
        import webview
    except ImportError:
        print("ERROR: pywebview >=5.0 is required. Install it with:")
        print("  pip install 'pywebview>=5.0'")
        print()
        print("On Linux, you may also need one of these backends:")
        print("  pip install 'pywebview[qt]>=5.0'    # For Qt backend")
        print("  pip install 'pywebview[gtk]>=5.0'   # For GTK backend")
        print("  pip install 'pywebview[cef]>=5.0'   # For CEF backend")
        sys.exit(1)

    if config is None:
        config = load_config()

    api = DesktopAPI(config)

    # Write HTML to a temp file so WebKit executes inline scripts
    import tempfile
    html_dir = os.path.join(tempfile.gettempdir(), 'tt-desktop')
    os.makedirs(html_dir, exist_ok=True)
    html_path = os.path.join(html_dir, 'index.html')
    with open(html_path, 'w', encoding='utf-8') as f:
        f.write(DESKTOP_HTML)

    # Create the webview window
    window = webview.create_window(
        title="TaskingBot AI",
        url=html_path,
        width=340,
        height=620,
        resizable=True,
        min_size=(280, 400),
        js_api=api,
        text_select=True,
    )

    api.set_window(window)

    def on_loaded():
        """Called when the webview finishes loading."""
        # Re-write HTML from source so hot-reload (F5) picks up changes
        try:
            with open(html_path, 'w', encoding='utf-8') as _f:
                _f.write(DESKTOP_HTML)
        except Exception:
            pass
        _start_poller_background(config, api, window)

    window.events.loaded += on_loaded

    def on_closing():
        """Clean up when window closes."""
        if api.poller:
            api.poller.running = False
            api.poller.disconnect()

    window.events.closing += on_closing

    # Start the webview (blocks until window is closed)
    webview.start(debug=False)


def main():
    """Entry point for `tt-desktop app` or direct execution."""
    launch_app()


if __name__ == "__main__":
    main()
