"""CLI authentication via GitHub OAuth.

Flow:
1. Start a temporary local HTTP server on a random port
2. Open the browser to the API's /auth/login?cli_port=PORT
3. GitHub OAuth happens in the browser
4. API callback generates an API key and redirects to http://localhost:PORT/callback
5. Local server catches the redirect, saves credentials, shows success page
"""

import json
import os
import socket
import threading
import webbrowser
from http.server import HTTPServer, BaseHTTPRequestHandler
from pathlib import Path
from urllib.parse import urlparse, parse_qs

CREDENTIALS_DIR = Path.home() / ".nbench"
CREDENTIALS_PATH = CREDENTIALS_DIR / "credentials.json"


def load_credentials() -> dict:
    """Load saved credentials from disk."""
    if CREDENTIALS_PATH.exists():
        try:
            return json.loads(CREDENTIALS_PATH.read_text())
        except (json.JSONDecodeError, OSError):
            pass
    return {}


def save_credentials(api_key: str, handle: str, api_url: str) -> None:
    """Save credentials to disk."""
    CREDENTIALS_DIR.mkdir(parents=True, exist_ok=True)
    CREDENTIALS_PATH.write_text(json.dumps({
        "api_key": api_key,
        "handle": handle,
        "api_url": api_url,
    }, indent=2))
    # Restrict permissions
    CREDENTIALS_PATH.chmod(0o600)


def _find_free_port() -> int:
    """Find an available port."""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.bind(("", 0))
        return s.getsockname()[1]


def run_login(api_url: str) -> dict | None:
    """Run the OAuth login flow. Returns {"api_key": ..., "handle": ...} or None."""
    port = _find_free_port()
    result = {}
    server_ready = threading.Event()

    class CallbackHandler(BaseHTTPRequestHandler):
        def do_GET(self):
            parsed = urlparse(self.path)
            if parsed.path == "/callback":
                params = parse_qs(parsed.query)
                api_key = params.get("api_key", [None])[0]
                handle = params.get("handle", [None])[0]

                if api_key and handle:
                    result["api_key"] = api_key
                    result["handle"] = handle
                    save_credentials(api_key, handle, api_url)

                    self.send_response(200)
                    self.send_header("Content-Type", "text/html")
                    self.end_headers()
                    self.wfile.write(b"""<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
                        <h2>Signed in successfully!</h2>
                        <p>You can close this tab and return to your terminal.</p>
                        <script>setTimeout(()=>window.close(),2000)</script>
                        </body></html>""")
                else:
                    self.send_response(400)
                    self.send_header("Content-Type", "text/html")
                    self.end_headers()
                    self.wfile.write(b"""<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
                        <h2>Login failed</h2><p>Missing credentials in callback.</p>
                        </body></html>""")

                # Shut down server after handling
                threading.Thread(target=self.server.shutdown, daemon=True).start()
            else:
                self.send_response(404)
                self.end_headers()

        def log_message(self, format, *args):
            pass  # Suppress request logs

    server = HTTPServer(("localhost", port), CallbackHandler)

    # Start server in background
    server_thread = threading.Thread(target=server.serve_forever, daemon=True)
    server_thread.start()

    # Open browser
    login_url = f"{api_url}/auth/login?cli_port={port}"
    print(f"Opening browser for GitHub login...")
    print(f"If it doesn't open, visit: {login_url}")
    webbrowser.open(login_url)

    # Wait for callback (timeout after 120 seconds)
    server_thread.join(timeout=120)
    server.server_close()

    return result if result else None
