"""Web server for QR code pairing flow.

Changes:
  - 2026-02-03: Optimised deep link flow. Now fetches bot username and listens for /start <secret>.
"""

import asyncio
import secrets
from typing import Optional
import logging

from fastapi import FastAPI, Request, Form
from fastapi.responses import HTMLResponse
import uvicorn
import qrcode
import qrcode.image.svg
from io import BytesIO
import base64

# Telegram imports for pairing bot
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes

from pocketclaw.config import Settings

logger = logging.getLogger(__name__)

# Global state for pairing
_pairing_complete = asyncio.Event()
_session_secret: Optional[str] = None
_settings: Optional[Settings] = None
_temp_bot_app: Optional[Application] = None


def generate_qr_svg(deep_link: str) -> str:
    """Generate QR code as SVG string."""
    qr = qrcode.QRCode(version=1, box_size=10, border=2)
    qr.add_data(deep_link)
    qr.make(fit=True)
    
    # Generate as PNG and convert to base64
    img = qr.make_image(fill_color="black", back_color="white")
    buffer = BytesIO()
    img.save(buffer, format="PNG")
    img_base64 = base64.b64encode(buffer.getvalue()).decode()
    return f"data:image/png;base64,{img_base64}"


async def _handle_pairing_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Handle /start <secret> during pairing."""
    global _settings, _pairing_complete
    
    if not update.message or not update.effective_user:
        return
        
    text = update.message.text
    if not text:
        return

    # Check payload
    # Format: /start <secret>
    # Note: Telegram sends "/start" or "/start <payload>"
    parts = text.split()
    
    if len(parts) < 2:
        await update.message.reply_text(
            "⏳ Waiting for pairing... Please scan the QR code to start."
        )
        return
        
    secret = parts[1]
    
    if secret != _session_secret:
        await update.message.reply_text("❌ Invalid session token. Please refresh the setup page.")
        return
        
    # Success!
    user_id = update.effective_user.id
    username = update.effective_user.username
    
    if _settings:
        _settings.allowed_user_id = user_id
        _settings.save()
        
    logger.info(f"✅ Paired with user: {username} ({user_id})")
    
    await update.message.reply_text(
        "🎉 **Connected!**\n\nPocketPaw is now paired with this device.\nYou can close the browser window now.",
        parse_mode="Markdown"
    )
    
    _pairing_complete.set()


def create_app(settings: Settings) -> FastAPI:
    """Create the FastAPI app for pairing."""
    global _session_secret, _settings
    _settings = settings
    _session_secret = secrets.token_urlsafe(32)
    
    app = FastAPI(title="PocketPaw Setup")
    
    @app.get("/", response_class=HTMLResponse)
    async def setup_page():
        """Render the setup page."""
        return f"""
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PocketPaw Setup</title>
    <style>
        * {{ margin: 0; padding: 0; box-sizing: border-box; }}
        body {{
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #fff;
        }}
        .container {{
            background: rgba(255,255,255,0.05);
            backdrop-filter: blur(10px);
            border-radius: 24px;
            padding: 48px;
            max-width: 480px;
            width: 90%;
            text-align: center;
            border: 1px solid rgba(255,255,255,0.1);
        }}
        .logo {{ font-size: 64px; margin-bottom: 16px; }}
        h1 {{ font-size: 28px; margin-bottom: 8px; }}
        .tagline {{ color: #888; margin-bottom: 32px; }}
        .step {{ 
            background: rgba(255,255,255,0.05); 
            border-radius: 12px; 
            padding: 20px; 
            margin-bottom: 16px;
            text-align: left;
        }}
        .step-number {{
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            width: 28px; height: 28px;
            border-radius: 50%;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 14px;
            margin-right: 12px;
        }}
        input {{
            width: 100%;
            padding: 14px 16px;
            border: 1px solid rgba(255,255,255,0.2);
            border-radius: 8px;
            background: rgba(0,0,0,0.3);
            color: #fff;
            font-size: 14px;
            margin-top: 12px;
        }}
        input:focus {{ outline: none; border-color: #667eea; }}
        button {{
            width: 100%;
            padding: 16px;
            border: none;
            border-radius: 12px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: #fff;
            font-size: 16px;
            font-weight: 600;
            cursor: pointer;
            margin-top: 24px;
            transition: transform 0.2s, box-shadow 0.2s;
        }}
        button:hover {{ transform: translateY(-2px); box-shadow: 0 8px 24px rgba(102,126,234,0.4); }}
        .qr-section {{ display: none; margin-top: 32px; }}
        .qr-section.active {{ display: block; }}
        .qr-code {{ 
            background: #fff; 
            padding: 16px; 
            border-radius: 16px; 
            display: inline-block;
            margin: 16px 0;
        }}
        .qr-code img {{ width: 200px; height: 200px; }}
        .success {{ 
            background: rgba(34, 197, 94, 0.2); 
            border: 1px solid rgba(34, 197, 94, 0.5);
            padding: 16px;
            border-radius: 12px;
            margin-top: 16px;
            animation: fadeIn 0.5s ease-out;
        }}
        @keyframes fadeIn {{ from {{ opacity: 0; transform: translateY(10px); }} to {{ opacity: 1; transform: translateY(0); }} }}
        .api-keys {{
            margin-top: 16px;
            text-align: left;
        }}
        .api-keys label {{
            display: block;
            font-size: 12px;
            color: #888;
            margin-top: 12px;
            margin-bottom: 4px;
        }}
    </style>
</head>
<body>
    <div class="container">
        <div class="logo">🦀</div>
        <h1>PocketPaw Setup</h1>
        <p class="tagline">Your AI agent, on your machine</p>
        
        <form id="setup-form" method="POST" action="/setup">
            <div class="step">
                <span class="step-number">1</span>
                <strong>Create a Telegram Bot</strong>
                <p style="color: #888; font-size: 14px; margin-top: 8px;">
                    Open <a href="https://t.me/BotFather" target="_blank" style="color: #667eea;">@BotFather</a> 
                    on Telegram and send <code>/newbot</code>
                </p>
                <input type="text" name="bot_token" placeholder="Paste your bot token here..." required>
            </div>
            
            <div class="step api-keys">
                <span class="step-number">2</span>
                <strong>LLM API Keys (Optional)</strong>
                <p style="color: #888; font-size: 14px; margin-top: 8px;">
                    Add API keys for cloud LLMs. Leave blank to use local Ollama only.
                </p>
                <label>OpenAI API Key</label>
                <input type="password" name="openai_key" placeholder="sk-...">
                <label>Anthropic API Key</label>
                <input type="password" name="anthropic_key" placeholder="sk-ant-...">
            </div>
            
            <button type="submit">Generate QR Code →</button>
        </form>
        
        <div id="qr-section" class="qr-section">
            <div class="step">
                <span class="step-number">3</span>
                <strong>Scan with Telegram</strong>
                <p style="color: #888; font-size: 14px; margin-top: 8px;">
                    Open your phone camera and scan this QR code
                </p>
            </div>
            <div class="qr-code">
                <img id="qr-image" src="" alt="QR Code">
            </div>
            <p style="color: #888; font-size: 14px;">Waiting for connection...</p>
        </div>
        
        <div id="success-section" class="success" style="display: none;">
            ✅ <strong>Connected!</strong> PocketPaw is now running.
        </div>
    </div>
    
    <script>
        document.getElementById('setup-form').addEventListener('submit', async (e) => {{
            e.preventDefault();
            const btn = e.target.querySelector('button');
            const originalText = btn.innerText;
            btn.innerText = "Connecting...";
            btn.disabled = true;
            
            const formData = new FormData(e.target);
            try {{
                const response = await fetch('/setup', {{
                    method: 'POST',
                    body: formData
                }});
                const data = await response.json();
                if (data.error) {{
                    alert(data.error);
                    btn.innerText = originalText;
                    btn.disabled = false;
                    return;
                }}
                if (data.qr_url) {{
                    document.getElementById('qr-image').src = data.qr_url;
                    document.getElementById('qr-section').classList.add('active');
                    e.target.style.display = 'none';
                    pollStatus();
                }}
            }} catch (err) {{
                alert("Failed to connect. Please check your internet.");
                btn.innerText = originalText;
                btn.disabled = false;
            }}
        }});
        
        async function pollStatus() {{
            while (true) {{
                try {{
                    const response = await fetch('/status');
                    const data = await response.json();
                    if (data.paired) {{
                        document.getElementById('qr-section').style.display = 'none';
                        document.getElementById('success-section').style.display = 'block';
                        setTimeout(() => window.close(), 3000);
                        break;
                    }}
                }} catch (e) {{ console.error(e); }}
                await new Promise(r => setTimeout(r, 1000));
            }}
        }}
    </script>
</body>
</html>
"""
    
    @app.post("/setup")
    async def setup(
        bot_token: str = Form(...),
        openai_key: Optional[str] = Form(None),
        anthropic_key: Optional[str] = Form(None)
    ):
        """Handle setup form submission."""
        global _settings, _temp_bot_app
        
        # Save the bot token
        _settings.telegram_bot_token = bot_token
        if openai_key:
            _settings.openai_api_key = openai_key
        if anthropic_key:
            _settings.anthropic_api_key = anthropic_key
        
        try:
            # 1. Initialize temporary bot
            builder = Application.builder().token(bot_token)
            app = builder.build()
            
            # 2. Verify token and get username
            bot_user = await app.bot.get_me()
            username = bot_user.username
            
            # 3. Generate Deep Link
            # Format: https://t.me/<username>?start=<secret>
            deep_link = f"https://t.me/{username}?start={_session_secret}"
            qr_data = generate_qr_svg(deep_link)
            
            # 4. Start Listening for /start <secret>
            app.add_handler(CommandHandler("start", _handle_pairing_start))
            
            await app.initialize()
            await app.start()
            await app.updater.start_polling(drop_pending_updates=True)
            
            _temp_bot_app = app
            
            return {"qr_url": qr_data, "session_secret": _session_secret}
            
        except Exception as e:
            logger.error(f"Setup failed: {e}")
            return {"error": f"Failed to connect to Telegram: {str(e)}"}
    
    @app.get("/status")
    async def status():
        """Check pairing status."""
        return {"paired": _pairing_complete.is_set()}
    
    @app.post("/complete")
    async def complete(user_id: int):
        """Called internally when pairing is complete."""
        global _settings
        _settings.allowed_user_id = user_id
        _settings.save()
        _pairing_complete.set()
        return {"ok": True}
    
    return app


async def run_pairing_server(settings: Settings) -> None:
    """Run the pairing server until pairing is complete."""
    app = create_app(settings)
    
    config = uvicorn.Config(
        app,
        host=settings.web_host,
        port=settings.web_port,
        log_level="warning"
    )
    server = uvicorn.Server(config)
    
    # Run server in background
    server_task = asyncio.create_task(server.serve())
    
    try:
        # Wait for pairing to complete
        await _pairing_complete.wait()
        
        # Give a moment for the success response to return
        await asyncio.sleep(1)
        
    finally:
        # Shutdown temporary bot
        global _temp_bot_app
        if _temp_bot_app:
            if _temp_bot_app.updater.running:
                await _temp_bot_app.updater.stop()
            if _temp_bot_app.running:
                await _temp_bot_app.stop()
            await _temp_bot_app.shutdown()
            
        # Shutdown web server
        server.should_exit = True
        await server_task
