"""
OAuth authentication with Google and GitHub.
"""
import os
import httpx
import secrets
import structlog
from typing import Optional, Dict
from app.core.auth import jwt_auth

logger = structlog.get_logger(__name__)

class OAuthProvider:
    """Base OAuth provider."""
    
    def __init__(self, client_id: str, client_secret: str, redirect_uri: str):
        self.client_id = client_id
        self.client_secret = client_secret
        self.redirect_uri = redirect_uri
        
    async def get_user_info(self, code: str) -> Optional[Dict]:
        """Exchange code for user info."""
        raise NotImplementedError


class GoogleOAuth(OAuthProvider):
    """Google OAuth 2.0 provider."""
    
    def __init__(self):
        super().__init__(
            client_id=os.getenv("GOOGLE_CLIENT_ID", ""),
            client_secret=os.getenv("GOOGLE_CLIENT_SECRET", ""),
            redirect_uri=os.getenv("GOOGLE_REDIRECT_URI", "http://localhost:3000/auth/google/callback")
        )
        self.token_url = "https://oauth2.googleapis.com/token"
        self.user_info_url = "https://www.googleapis.com/oauth2/v2/userinfo"
        
    def get_authorization_url(self, state: str) -> str:
        """Get Google OAuth authorization URL."""
        params = {
            "client_id": self.client_id,
            "redirect_uri": self.redirect_uri,
            "response_type": "code",
            "scope": "openid email profile",
            "state": state
        }
        query = "&".join(f"{k}={v}" for k, v in params.items())
        return f"https://accounts.google.com/o/oauth2/v2/auth?{query}"
        
    async def get_user_info(self, code: str) -> Optional[Dict]:
        """Exchange code for user info."""
        try:
            async with httpx.AsyncClient() as client:
                # Exchange code for token
                token_response = await client.post(
                    self.token_url,
                    data={
                        "code": code,
                        "client_id": self.client_id,
                        "client_secret": self.client_secret,
                        "redirect_uri": self.redirect_uri,
                        "grant_type": "authorization_code"
                    }
                )
                token_response.raise_for_status()
                token_data = token_response.json()
                
                # Get user info
                user_response = await client.get(
                    self.user_info_url,
                    headers={"Authorization": f"Bearer {token_data['access_token']}"}
                )
                user_response.raise_for_status()
                user_data = user_response.json()
                
                return {
                    "provider": "google",
                    "provider_id": user_data["id"],
                    "email": user_data["email"],
                    "name": user_data.get("name", ""),
                    "avatar_url": user_data.get("picture", "")
                }
        except Exception as e:
            logger.error("google_oauth_failed", error=str(e))
            return None


class GitHubOAuth(OAuthProvider):
    """GitHub OAuth provider."""
    
    def __init__(self):
        super().__init__(
            client_id=os.getenv("GITHUB_CLIENT_ID", ""),
            client_secret=os.getenv("GITHUB_CLIENT_SECRET", ""),
            redirect_uri=os.getenv("GITHUB_REDIRECT_URI", "http://localhost:3000/auth/github/callback")
        )
        self.token_url = "https://github.com/login/oauth/access_token"
        self.user_info_url = "https://api.github.com/user"
        
    def get_authorization_url(self, state: str) -> str:
        """Get GitHub OAuth authorization URL."""
        params = {
            "client_id": self.client_id,
            "redirect_uri": self.redirect_uri,
            "scope": "read:user user:email",
            "state": state
        }
        query = "&".join(f"{k}={v}" for k, v in params.items())
        return f"https://github.com/login/oauth/authorize?{query}"
        
    async def get_user_info(self, code: str) -> Optional[Dict]:
        """Exchange code for user info."""
        try:
            async with httpx.AsyncClient() as client:
                # Exchange code for token
                token_response = await client.post(
                    self.token_url,
                    headers={"Accept": "application/json"},
                    data={
                        "code": code,
                        "client_id": self.client_id,
                        "client_secret": self.client_secret,
                        "redirect_uri": self.redirect_uri
                    }
                )
                token_response.raise_for_status()
                token_data = token_response.json()
                
                # Get user info
                user_response = await client.get(
                    self.user_info_url,
                    headers={"Authorization": f"Bearer {token_data['access_token']}"}
                )
                user_response.raise_for_status()
                user_data = user_response.json()
                
                return {
                    "provider": "github",
                    "provider_id": str(user_data["id"]),
                    "email": user_data.get("email", ""),
                    "name": user_data.get("name", user_data.get("login", "")),
                    "avatar_url": user_data.get("avatar_url", "")
                }
        except Exception as e:
            logger.error("github_oauth_failed", error=str(e))
            return None


# Global instances
google_oauth = GoogleOAuth()
github_oauth = GitHubOAuth()
