"""OAuth authentication and token refresh."""

import webbrowser
import socket
from http.server import HTTPServer, BaseHTTPRequestHandler
from datetime import datetime, timedelta
import requests
from urllib.parse import urlparse, parse_qs
from mcpbundles_proxy.config import save_token


def find_free_port(start_port=8765, max_attempts=10):
    """Find available port starting from start_port."""
    for port in range(start_port, start_port + max_attempts):
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                s.bind(('localhost', port))
                return port
        except OSError:
            continue
    raise RuntimeError("Could not find available port for OAuth callback")


class OAuthCallbackHandler(BaseHTTPRequestHandler):
    """Handle OAuth callback from browser."""
    
    auth_code: str | None = None
    
    def do_GET(self):
        """Handle GET request with OAuth code."""
        query = parse_qs(urlparse(self.path).query)
        OAuthCallbackHandler.auth_code = query.get('code', [None])[0]
        
        # Show success page in browser
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        html = """
            <html>
            <head>
                <style>
                    body {
                        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
                        text-align: center;
                        padding: 50px;
                        background: #f5f5f5;
                    }
                    .container {
                        background: white;
                        border-radius: 10px;
                        padding: 40px;
                        max-width: 500px;
                        margin: 0 auto;
                        box-shadow: 0 2px 10px rgba(0,0,0,0.1);
                    }
                    h1 { color: #28a745; }
                </style>
            </head>
            <body>
                <div class="container">
                    <h1>&#x2705; Authentication Successful</h1>
                    <p>You can close this window and return to your terminal.</p>
                </div>
            </body>
            </html>
        """
        self.wfile.write(html.encode('utf-8'))
    
    def log_message(self, format, *args):
        """Suppress HTTP server logs."""
        pass


def oauth_flow():
    """Execute OAuth flow with browser and local callback server."""
    # Find available port
    port = find_free_port()
    redirect_uri = f"http://localhost:{port}/callback"
    
    # Start local callback server
    server = HTTPServer(('localhost', port), OAuthCallbackHandler)
    
    # Open browser to OAuth page
    auth_url = (
        f"https://mcpbundles.com/oauth/authorize"
        f"?client_id=proxy"
        f"&redirect_uri={redirect_uri}"
        f"&response_type=code"
    )
    
    print(f"Opening browser for authentication...")
    print(f"If browser doesn't open, visit: {auth_url}")
    webbrowser.open(auth_url)
    
    # Wait for callback (with timeout)
    server.timeout = 120  # 2 minute timeout
    server.handle_request()
    
    if not OAuthCallbackHandler.auth_code:
        raise Exception("Authentication failed or timed out")
    
    # Exchange code for tokens
    print("Exchanging authorization code for tokens...")
    response = requests.post(
        "https://api.mcpbundles.com/oauth/token",
        json={
            "code": OAuthCallbackHandler.auth_code,
            "client_id": "proxy",
            "redirect_uri": redirect_uri
        }
    )
    
    if response.status_code != 200:
        raise Exception(f"Token exchange failed: {response.text}")
    
    token_data = response.json()
    
    # Add expiry timestamp
    expires_in = token_data.get('expires_in', 86400)  # Default 1 day
    token_data['expires_at'] = (
        datetime.now() + timedelta(seconds=expires_in)
    ).isoformat()
    
    # Save tokens
    save_token(token_data)
    print(f"✅ Successfully authenticated!")
    
    return token_data


async def refresh_token_if_needed(token_data):
    """Check and refresh access token if needed."""
    expires_at = datetime.fromisoformat(token_data['expires_at'])
    
    # Refresh if expires in less than 1 hour
    if datetime.now() >= expires_at - timedelta(hours=1):
        try:
            print("Refreshing access token...")
            response = requests.post(
                "https://api.mcpbundles.com/oauth/refresh",
                json={
                    "refresh_token": token_data['refresh_token'],
                    "client_id": "proxy"
                }
            )
            
            if response.status_code == 200:
                new_token = response.json()
                expires_in = new_token.get('expires_in', 86400)
                new_token['expires_at'] = (
                    datetime.now() + timedelta(seconds=expires_in)
                ).isoformat()
                # Keep refresh token
                new_token['refresh_token'] = token_data['refresh_token']
                save_token(new_token)
                print("✅ Token refreshed")
                return new_token
            else:
                # Refresh failed, need to re-authenticate
                print("⚠️ Token refresh failed, re-authentication needed")
                return None
        except Exception as e:
            print(f"❌ Token refresh error: {e}")
            return None
    
    return token_data

