"""Local OAuth callback server for handling redirects.

This module implements a local HTTP server that handles OAuth authorization
callbacks during the Authorization Code flow.
"""

import asyncio
from typing import Optional, Tuple

from aiohttp import web


class OAuthCallbackServer:
    """HTTP server for receiving OAuth authorization callbacks.

    Runs a local web server that listens for OAuth redirect callbacks,
    extracts the authorization code or error, and returns it to the flow.
    """

    def __init__(self, port: int = 31415):
        """Initialize callback server.

        Args:
            port: Port to listen on (default 31415)
        """
        self.port = port
        self.code: Optional[str] = None
        self.error: Optional[str] = None
        self.error_description: Optional[str] = None
        self._app: Optional[web.Application] = None
        self._runner: Optional[web.AppRunner] = None
        self._site: Optional[web.TCPSite] = None
        self._callback_event = asyncio.Event()

    async def start(self, timeout: int = 300) -> Tuple[Optional[str], Optional[str]]:
        """Start server and wait for callback.

        Args:
            timeout: Maximum time to wait in seconds (default 5 minutes)

        Returns:
            Tuple of (authorization_code, error). One will be None, the other set.

        Raises:
            TimeoutError: If no callback received within timeout
        """
        # Create app and routes
        self._app = web.Application()
        self._app.router.add_get("/oauth/callback", self._handle_callback)
        self._app.router.add_get("/", self._handle_root)

        # Start server
        self._runner = web.AppRunner(self._app)
        await self._runner.setup()

        try:
            self._site = web.TCPSite(self._runner, "localhost", self.port)
            await self._site.start()
            print(f"✓ OAuth callback server listening on http://localhost:{self.port}")

            # Wait for callback or timeout
            try:
                await asyncio.wait_for(
                    self._callback_event.wait(), timeout=timeout
                )
            except asyncio.TimeoutError:
                return None, "timeout"

            return self.code, self.error

        except OSError as e:
            # Port might be in use, try a different port
            if "Address already in use" in str(e):
                print(f"⚠️  Port {self.port} is in use, trying {self.port + 1}...")
                self.port += 1
                return await self.start(timeout)
            raise

    async def stop(self):
        """Stop the callback server."""
        if self._site:
            await self._site.stop()
        if self._runner:
            await self._runner.cleanup()

    async def _handle_callback(self, request: web.Request) -> web.Response:
        """Handle OAuth callback request.

        Args:
            request: HTTP request with OAuth callback parameters

        Returns:
            HTML response showing success or error
        """
        # Extract parameters
        self.code = request.query.get("code")
        self.error = request.query.get("error")
        self.error_description = request.query.get("error_description")

        # Signal that callback was received
        self._callback_event.set()

        # Return appropriate HTML
        if self.error:
            return web.Response(
                text=self._error_html(self.error, self.error_description),
                content_type="text/html",
            )
        else:
            return web.Response(
                text=self._success_html(),
                content_type="text/html",
            )

    async def _handle_root(self, request: web.Request) -> web.Response:
        """Handle root path request.

        Args:
            request: HTTP request

        Returns:
            HTML response
        """
        return web.Response(
            text=self._waiting_html(),
            content_type="text/html",
        )

    @staticmethod
    def _success_html() -> str:
        """Generate success HTML page.

        Returns:
            HTML content for successful authorization
        """
        return """
<!DOCTYPE html>
<html>
<head>
    <title>Authorization Successful</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            display: flex;
            align-items: center;
            justify-content: center;
            height: 100vh;
            margin: 0;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        }
        .container {
            background: white;
            padding: 3rem;
            border-radius: 10px;
            box-shadow: 0 10px 40px rgba(0,0,0,0.1);
            text-align: center;
            max-width: 500px;
        }
        .icon {
            font-size: 4rem;
            margin-bottom: 1rem;
        }
        h1 {
            color: #2d3748;
            margin-bottom: 1rem;
        }
        p {
            color: #4a5568;
            line-height: 1.6;
        }
        .close-note {
            margin-top: 2rem;
            padding: 1rem;
            background: #f7fafc;
            border-radius: 5px;
            color: #718096;
            font-size: 0.9rem;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="icon">✅</div>
        <h1>Authorization Successful!</h1>
        <p>You have successfully authorized groknroll to access the MCP server.</p>
        <p>You can now close this window and return to your terminal.</p>
        <div class="close-note">
            This window can be safely closed.
        </div>
    </div>
    <script>
        // Auto-close after 3 seconds
        setTimeout(() => {
            window.close();
        }, 3000);
    </script>
</body>
</html>
"""

    @staticmethod
    def _error_html(error: str, error_description: Optional[str] = None) -> str:
        """Generate error HTML page.

        Args:
            error: Error code
            error_description: Optional error description

        Returns:
            HTML content for authorization error
        """
        description = error_description or "An error occurred during authorization."
        return f"""
<!DOCTYPE html>
<html>
<head>
    <title>Authorization Failed</title>
    <style>
        body {{
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            display: flex;
            align-items: center;
            justify-content: center;
            height: 100vh;
            margin: 0;
            background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
        }}
        .container {{
            background: white;
            padding: 3rem;
            border-radius: 10px;
            box-shadow: 0 10px 40px rgba(0,0,0,0.1);
            text-align: center;
            max-width: 500px;
        }}
        .icon {{
            font-size: 4rem;
            margin-bottom: 1rem;
        }}
        h1 {{
            color: #2d3748;
            margin-bottom: 1rem;
        }}
        p {{
            color: #4a5568;
            line-height: 1.6;
        }}
        .error-code {{
            margin-top: 2rem;
            padding: 1rem;
            background: #fff5f5;
            border-radius: 5px;
            color: #c53030;
            font-family: monospace;
            font-size: 0.9rem;
        }}
        .close-note {{
            margin-top: 1rem;
            color: #718096;
            font-size: 0.9rem;
        }}
    </style>
</head>
<body>
    <div class="container">
        <div class="icon">❌</div>
        <h1>Authorization Failed</h1>
        <p>{description}</p>
        <div class="error-code">
            Error: {error}
        </div>
        <div class="close-note">
            You can close this window and return to your terminal.
        </div>
    </div>
</body>
</html>
"""

    @staticmethod
    def _waiting_html() -> str:
        """Generate waiting HTML page.

        Returns:
            HTML content for waiting state
        """
        return """
<!DOCTYPE html>
<html>
<head>
    <title>Waiting for Authorization</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            display: flex;
            align-items: center;
            justify-content: center;
            height: 100vh;
            margin: 0;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        }
        .container {
            background: white;
            padding: 3rem;
            border-radius: 10px;
            box-shadow: 0 10px 40px rgba(0,0,0,0.1);
            text-align: center;
            max-width: 500px;
        }
        .spinner {
            border: 4px solid #f3f3f3;
            border-top: 4px solid #667eea;
            border-radius: 50%;
            width: 50px;
            height: 50px;
            animation: spin 1s linear infinite;
            margin: 0 auto 2rem;
        }
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        h1 {
            color: #2d3748;
            margin-bottom: 1rem;
        }
        p {
            color: #4a5568;
            line-height: 1.6;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="spinner"></div>
        <h1>Waiting for Authorization</h1>
        <p>Please complete the authorization in your OAuth provider's window.</p>
        <p>This page will update automatically once authorization is complete.</p>
    </div>
</body>
</html>
"""
