"""
Browser-based login flow for SigmanticAI CLI.

Supports:
  - Email/password login
  - Google OAuth
  - GitHub OAuth
  - Headless login (REST API, no browser)

Flow:
  1. CLI opens a local HTTP server on a random port
  2. Opens the browser to sigmanticai.com/login.html
  3. User authenticates → JS redirects to localhost/callback with tokens
  4. CLI saves tokens to ~/.sigmanticai/credentials.json
"""

from __future__ import annotations

import http.server
import json
import socket
import ssl
import threading
import time
import urllib.parse
import webbrowser
from typing import Any, Dict, Optional

import certifi

from sigmanticai.auth.credentials import (
    SUPABASE_URL,
    SUPABASE_ANON_KEY,
    save_credentials,
)


def headless_login(email: str, password: str) -> Optional[Dict[str, Any]]:
    """
    Login via the Gateway API — no browser, no SDK needed.

    Primary path: POST /v1/auth/login on the Gateway (validates email
    confirmation server-side).

    Fallback: If the Gateway is unreachable (e.g. local-only dev),
    falls back to the Supabase REST API directly.

    Usage: sigmanticai login --email user@example.com --password secret
    """
    import urllib.request
    import urllib.error as _ue

    # ── Primary: call Gateway API (same as AuthClient.login) ──────
    from sigmanticai.auth.client import API_BASE_URL

    try:
        ssl_ctx = ssl.create_default_context(cafile=certifi.where())
        gateway_url = f"{API_BASE_URL}/v1/auth/login"
        payload = json.dumps({"email": email, "password": password}).encode()
        headers = {"Content-Type": "application/json"}
        req = urllib.request.Request(gateway_url, data=payload, headers=headers, method="POST")
        with urllib.request.urlopen(req, timeout=15, context=ssl_ctx) as resp:
            data = json.loads(resp.read())

        access_token = data.get("access_token", "")
        refresh_token = data.get("refresh_token", "")
        if not access_token:
            print("Login failed: no access token returned")
            return None

        creds = {
            "access_token": access_token,
            "refresh_token": refresh_token,
            "timestamp": time.time(),
        }
        save_credentials(creds)
        return creds

    except _ue.HTTPError as e:
        try:
            err_body = json.loads(e.read())
            msg = err_body.get("detail") or err_body.get("error_description") or str(e)
        except Exception:
            msg = str(e)
        print(f"Login failed: {msg}")
        return None

    except (urllib.error.URLError, OSError):
        # Gateway unreachable — fall back to direct Supabase REST API
        # (useful for offline / local-only development)
        pass

    # ── Fallback: direct Supabase REST API ────────────────────────
    try:
        url = f"{SUPABASE_URL}/auth/v1/token?grant_type=password"
        body = json.dumps({"email": email, "password": password}).encode()
        headers = {
            "apikey": SUPABASE_ANON_KEY,
            "Content-Type": "application/json",
        }

        ssl_ctx = ssl.create_default_context(cafile=certifi.where())
        req = urllib.request.Request(url, data=body, headers=headers, method="POST")
        with urllib.request.urlopen(req, timeout=15, context=ssl_ctx) as resp:
            data = json.loads(resp.read())
    except _ue.HTTPError as e:
        try:
            err_body = json.loads(e.read())
            msg = err_body.get("error_description") or err_body.get("msg") or str(e)
        except Exception:
            msg = str(e)
        print(f"Login failed: {msg}")
        return None
    except Exception as e:
        print(f"Login failed: {e}")
        return None

    access_token = data.get("access_token", "")
    refresh_token = data.get("refresh_token", "")
    if not access_token:
        print("Login failed: no access token returned")
        return None

    creds = {
        "access_token": access_token,
        "refresh_token": refresh_token,
        "timestamp": time.time(),
    }
    save_credentials(creds)
    return creds


def browser_login(timeout: int = 120) -> Optional[Dict[str, Any]]:
    """
    Launch browser-based login via sigmanticai.com.

    Opens the real website login page with a localhost callback URL.
    After the user authenticates, the website redirects tokens back
    to the local server.

    Returns credentials dict on success, None on failure/timeout.
    """
    # Find a free port
    with socket.socket() as s:
        s.bind(("", 0))
        port = s.getsockname()[1]

    callback_uri = f"http://localhost:{port}/callback"
    result: Dict[str, Any] = {"credentials": None}

    _SUCCESS_HTML = b"""<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>SigmanticAI</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>
  *{margin:0;padding:0;box-sizing:border-box}
  body{background:#09090b;color:#fafafa;font-family:'Inter',system-ui,sans-serif;
    display:flex;align-items:center;justify-content:center;min-height:100vh;
    background:linear-gradient(135deg,#09090b 0%,#1a0033 50%,#09090b 100%)}
  .card{text-align:center;padding:3rem 2.5rem;border-radius:16px;
    background:rgba(39,39,42,0.6);backdrop-filter:blur(10px);
    border:1px solid rgba(139,92,246,0.2);
    box-shadow:0 8px 32px rgba(0,0,0,0.3),0 0 0 1px rgba(139,92,246,0.1);
    max-width:420px;width:90%}
  .icon{width:48px;height:48px;margin:0 auto 1.2rem;border-radius:50%;
    background:linear-gradient(135deg,#8b5cf6,#6d28d9);
    display:flex;align-items:center;justify-content:center}
  .icon svg{width:28px;height:28px;stroke:#fff;fill:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}
  h1{font-size:1.5rem;font-weight:700;margin-bottom:0.5rem}
  p{color:#a1a1aa;font-size:0.95rem;margin-bottom:1.5rem}
  .bar{height:3px;border-radius:2px;background:rgba(139,92,246,0.15);overflow:hidden;width:60%;margin:0 auto}
  .bar span{display:block;height:100%;width:0;background:linear-gradient(90deg,#8b5cf6,#6d28d9);
    border-radius:2px;animation:fill 1.5s ease forwards}
  @keyframes fill{to{width:100%}}
  .sub{color:#71717a;font-size:0.8rem;margin-top:1rem}
</style></head>
<body><div class="card">
  <div class="icon"><svg viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg></div>
  <h1>You're logged in</h1>
  <p>Return to your terminal to continue.</p>
  <div class="bar"><span></span></div>
  <div class="sub">This tab will close automatically</div>
</div>
<script>setTimeout(function(){window.close()},2000)</script>
</body></html>"""

    _FAIL_HTML = b"""<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>SigmanticAI</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>
  *{margin:0;padding:0;box-sizing:border-box}
  body{background:#09090b;color:#fafafa;font-family:'Inter',system-ui,sans-serif;
    display:flex;align-items:center;justify-content:center;min-height:100vh;
    background:linear-gradient(135deg,#09090b 0%,#1a0033 50%,#09090b 100%)}
  .card{text-align:center;padding:3rem 2.5rem;border-radius:16px;
    background:rgba(39,39,42,0.6);backdrop-filter:blur(10px);
    border:1px solid rgba(139,92,246,0.2);
    box-shadow:0 8px 32px rgba(0,0,0,0.3),0 0 0 1px rgba(139,92,246,0.1);
    max-width:420px;width:90%}
  .icon{width:48px;height:48px;margin:0 auto 1.2rem;border-radius:50%;
    background:linear-gradient(135deg,#ef4444,#dc2626);
    display:flex;align-items:center;justify-content:center}
  .icon svg{width:28px;height:28px;stroke:#fff;fill:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}
  h1{font-size:1.5rem;font-weight:700;margin-bottom:0.5rem}
  p{color:#a1a1aa;font-size:0.95rem}
</style></head>
<body><div class="card">
  <div class="icon"><svg viewBox="0 0 24 24"><path d="M18 6L6 18M6 6l12 12"/></svg></div>
  <h1>Login failed</h1>
  <p>Go back to the terminal and try again.</p>
</div></body></html>"""

    class CallbackHandler(http.server.BaseHTTPRequestHandler):
        def do_GET(self):
            parsed = urllib.parse.urlparse(self.path)

            if parsed.path == "/callback":
                # Extract tokens from query params
                params = urllib.parse.parse_qs(parsed.query)
                access_token = params.get("access_token", [""])[0]
                refresh_token = params.get("refresh_token", [""])[0]

                if access_token:
                    result["credentials"] = {
                        "access_token": access_token,
                        "refresh_token": refresh_token,
                        "timestamp": time.time(),
                    }
                    save_credentials(result["credentials"])

                try:
                    if access_token:
                        self.send_response(200)
                        self.send_header("Content-Type", "text/html")
                        self.send_header("Connection", "close")
                        self.send_header("Cache-Control", "no-store")
                        self.end_headers()
                        self.wfile.write(_SUCCESS_HTML)
                    else:
                        self.send_response(400)
                        self.send_header("Content-Type", "text/html")
                        self.send_header("Connection", "close")
                        self.end_headers()
                        self.wfile.write(_FAIL_HTML)
                    self.wfile.flush()
                except BrokenPipeError:
                    pass  # Browser closed connection — credentials already saved

                # Delay shutdown so browser fully receives the response
                def _delayed_shutdown():
                    time.sleep(2)
                    self.server.shutdown()
                threading.Thread(target=_delayed_shutdown, daemon=True).start()

            else:
                try:
                    self.send_response(404)
                    self.end_headers()
                except BrokenPipeError:
                    pass

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

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

    # Open browser to sigmanticai.com login page with callback
    # fresh=true tells the page to clear any cached Supabase session
    # so the user always sees the login form and can pick an account
    login_url = (
        f"https://www.sigmanticai.com/login.html"
        f"?callback={urllib.parse.quote(callback_uri, safe='')}"
        f"&fresh=true"
    )
    print(f"Opening browser for login...")
    print(f"  If the browser doesn't open automatically, visit:")
    print(f"  {login_url}")
    print()
    try:
        opened = webbrowser.open(login_url)
        if not opened:
            raise OSError("webbrowser.open() returned False")
    except Exception:
        raise OSError(
            "Could not open a browser.\n\n"
            "  First, create an account at: https://www.sigmanticai.com/login.html\n\n"
            "  Then log in with one of:\n"
            "    Email/password:  sigmanticai login --email <email> --password <pw>\n"
            "    Google account:  sigmanticai login --google --email <your-gmail>"
        )

    # Wait for callback
    server_thread = threading.Thread(target=server.serve_forever)
    server_thread.daemon = True
    server_thread.start()
    server_thread.join(timeout=timeout)
    server.shutdown()

    return result.get("credentials")


def _build_login_html(supabase_url: str, anon_key: str, redirect_uri: str) -> str:
    """Build the HTML login page with Supabase JS SDK."""
    return f"""<!DOCTYPE html>
<html>
<head>
  <title>SigmanticAI Login</title>
  <script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>
  <style>
    body {{ font-family: -apple-system, system-ui, sans-serif; text-align: center;
           padding: 60px; background: #0a0a0a; color: #e0e0e0; }}
    h1 {{ color: #00d4ff; }}
    .btn {{ display: inline-block; padding: 14px 28px; margin: 10px;
            border-radius: 8px; font-size: 16px; cursor: pointer;
            border: none; font-weight: 600; }}
    .btn-google {{ background: #4285f4; color: white; }}
    .btn-github {{ background: #333; color: white; }}
    .btn:hover {{ opacity: 0.9; transform: scale(1.02); }}
    .divider {{ margin: 30px 0; color: #666; }}
    input {{ padding: 12px; margin: 5px; border-radius: 6px; border: 1px solid #333;
            background: #1a1a1a; color: white; width: 260px; font-size: 14px; }}
    .btn-email {{ background: #00d4ff; color: black; }}
  </style>
</head>
<body>
  <h1>&#x1F680; SigmanticAI</h1>
  <p>Sign in to your account</p>

  <button class="btn btn-google" onclick="loginGoogle()">Sign in with Google</button>
  <button class="btn btn-github" onclick="loginGitHub()">Sign in with GitHub</button>

  <div class="divider">— or —</div>

  <div>
    <input type="email" id="email" placeholder="Email" /><br/>
    <input type="password" id="password" placeholder="Password" /><br/>
    <button class="btn btn-email" onclick="loginEmail()">Sign in with Email</button>
  </div>

  <p id="status" style="color: #888; margin-top: 20px;"></p>

  <script>
    const sb = supabase.createClient('{supabase_url}', '{anon_key}');
    const redirectBase = '{redirect_uri}';

    async function loginGoogle() {{
      const {{ data, error }} = await sb.auth.signInWithOAuth({{
        provider: 'google',
        options: {{ redirectTo: window.location.origin + '/callback_oauth' }}
      }});
      if (error) document.getElementById('status').textContent = error.message;
    }}

    async function loginGitHub() {{
      const {{ data, error }} = await sb.auth.signInWithOAuth({{
        provider: 'github',
        options: {{ redirectTo: window.location.origin + '/callback_oauth' }}
      }});
      if (error) document.getElementById('status').textContent = error.message;
    }}

    async function loginEmail() {{
      const email = document.getElementById('email').value;
      const password = document.getElementById('password').value;
      document.getElementById('status').textContent = 'Signing in...';

      const {{ data, error }} = await sb.auth.signInWithPassword({{ email, password }});
      if (error) {{
        document.getElementById('status').textContent = error.message;
        return;
      }}

      if (data.session) {{
        const params = new URLSearchParams({{
          access_token: data.session.access_token,
          refresh_token: data.session.refresh_token,
        }});
        window.location.href = redirectBase + '?' + params.toString();
      }}
    }}

    // Check for hash fragment (OAuth redirect)
    if (window.location.hash) {{
      const params = new URLSearchParams(window.location.hash.substring(1));
      const access_token = params.get('access_token');
      const refresh_token = params.get('refresh_token');
      if (access_token) {{
        const qs = new URLSearchParams({{ access_token, refresh_token }});
        window.location.href = redirectBase + '?' + qs.toString();
      }}
    }}
  </script>
</body>
</html>"""

