#lsx OAuth认证管理器模块

import json
import logging
import time
from urllib.parse import urlencode, parse_qs

import requests
from django.conf import settings
from django.http import HttpResponseRedirect, JsonResponse
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from rest_framework.authtoken.models import Token

from accounts.models import BlogUser
from djangoblog.utils import get_sha256, get_current_site
from oauth.models import OAuthConfig, OAuthUser

logger = logging.getLogger(__name__)

#lsx OAuth认证类型枚举
class OAuthType:
    #lsx 定义支持的OAuth类型
    GITHUB = 'github'
    WEIBO = 'weibo'
    QQ = 'qq'
    GITEE = 'gitee'
    DINGTALK = 'dingtalk'
    BAIDU = 'baidu'

#lsx OAuth认证基类
class OAuthManagerBase:
    #lsx 初始化OAuth配置
    def __init__(self):
        #lsx 获取当前站点
        self.site = get_current_site()
        #lsx 获取OAuth配置
        self.config = None
    
    #lsx 获取授权URL
    def get_authorization_url(self):
        #lsx 生成state参数，防止CSRF攻击
        self.state = get_sha256(str(time.time()))
        #lsx 构建授权URL
        pass
    
    #lsx 处理回调
    def callback(self, request):
        #lsx 验证state参数
        #lsx 获取code
        #lsx 换取access_token
        #lsx 获取用户信息
        #lsx 处理登录或注册
        pass
    
    #lsx 获取access_token
    def get_access_token(self, code):
        #lsx 向OAuth提供商请求access_token
        pass
    
    #lsx 获取用户信息
    def get_user_info(self, access_token):
        #lsx 使用access_token获取用户信息
        pass
    
    #lsx 处理用户登录或注册
    def handle_user(self, user_info):
        #lsx 根据用户信息创建或更新用户
        pass

#lsx GitHub OAuth管理器
class GithubOAuthManager(OAuthManagerBase):
    #lsx 初始化GitHub OAuth配置
    def __init__(self):
        super().__init__()
        #lsx 获取GitHub OAuth配置
        self.config = OAuthConfig.objects.filter(type=OAuthType.GITHUB).first()
        self.oauth_type = OAuthType.GITHUB
    
    #lsx 获取GitHub授权URL
    def get_authorization_url(self):
        #lsx 生成state参数
        self.state = get_sha256(str(time.time()))
        #lsx 构建授权URL
        params = {
            'client_id': self.config.app_key,
            'redirect_uri': f'http://{self.site.domain}{reverse("oauth:oauth_callback", kwargs={"oauth_type": self.oauth_type})}',
            'state': self.state,
            'scope': 'user:email'
        }
        #lsx 授权URL
        return 'https://github.com/login/oauth/authorize?' + urlencode(params)
    
    #lsx 处理GitHub回调
    def callback(self, request):
        #lsx 验证state参数
        code = request.GET.get('code')
        if not code:
            return JsonResponse({'status': 'fail', 'msg': _('授权失败')})
        #lsx 获取access_token
        access_token = self.get_access_token(code)
        if not access_token:
            return JsonResponse({'status': 'fail', 'msg': _('获取token失败')})
        #lsx 获取用户信息
        user_info = self.get_user_info(access_token)
        if not user_info:
            return JsonResponse({'status': 'fail', 'msg': _('获取用户信息失败')})
        #lsx 处理用户登录或注册
        return self.handle_user(user_info)
    
    #lsx 获取GitHub access_token
    def get_access_token(self, code):
        #lsx 向GitHub请求access_token
        url = 'https://github.com/login/oauth/access_token'
        data = {
            'client_id': self.config.app_key,
            'client_secret': self.config.app_secret,
            'code': code
        }
        headers = {'Accept': 'application/json'}
        try:
            response = requests.post(url, data=data, headers=headers)
            result = response.json()
            return result.get('access_token')
        except Exception as e:
            logger.error(f'GitHub get_access_token error: {e}')
            return None
    
    #lsx 获取GitHub用户信息
    def get_user_info(self, access_token):
        #lsx 使用access_token获取GitHub用户信息
        url = 'https://api.github.com/user'
        headers = {'Authorization': f'token {access_token}'}
        try:
            response = requests.get(url, headers=headers)
            user_data = response.json()
            #lsx 获取用户邮箱
            emails_url = 'https://api.github.com/user/emails'
            emails_response = requests.get(emails_url, headers=headers)
            emails = emails_response.json()
            primary_email = None
            for email in emails:
                if email.get('primary'):
                    primary_email = email.get('email')
                    break
            #lsx 构建用户信息
            return {
                'username': user_data.get('login'),
                'email': primary_email or user_data.get('email', ''),
                'avatar': user_data.get('avatar_url'),
                'name': user_data.get('name') or user_data.get('login'),
                'id': user_data.get('id')
            }
        except Exception as e:
            logger.error(f'GitHub get_user_info error: {e}')
            return None
    
    #lsx 处理GitHub用户
    def handle_user(self, user_info):
        #lsx 查找或创建OAuth用户
        try:
            oauth_user = OAuthUser.objects.filter(
                oauth_type=self.oauth_type,
                oauth_id=str(user_info['id'])
            ).first()
            
            if oauth_user:
                #lsx 已存在OAuth用户，直接登录
                user = oauth_user.user
            else:
                #lsx 新用户，创建账号
                username = user_info['username']
                #lsx 检查用户名是否已存在
                while BlogUser.objects.filter(username=username).exists():
                    username += '_github'
                
                #lsx 创建用户
                user = BlogUser.objects.create_user(
                    username=username,
                    email=user_info['email'] or f'{username}@github.com',
                    password=get_sha256(str(time.time()))
                )
                #lsx 更新用户信息
                user.nickname = user_info['name'][:50]
                user.avatar = user_info['avatar']
                user.save()
                
                #lsx 创建OAuth用户关联
                OAuthUser.objects.create(
                    user=user,
                    oauth_type=self.oauth_type,
                    oauth_id=str(user_info['id']),
                    oauth_name=user_info['name'],
                    oauth_avatar=user_info['avatar']
                )
            
            #lsx 生成token
            token, _ = Token.objects.get_or_create(user=user)
            
            #lsx 设置登录状态
            from django.contrib.auth import login
            login(self.request, user)
            
            #lsx 重定向到首页
            return HttpResponseRedirect('/')
        except Exception as e:
            logger.error(f'GitHub handle_user error: {e}')
            return JsonResponse({'status': 'fail', 'msg': _('处理用户信息失败')})

#lsx OAuth管理器工厂类
class OAuthManager:
    #lsx OAuth管理器映射
    managers = {
        OAuthType.GITHUB: GithubOAuthManager,
        #lsx 可以添加其他OAuth类型的管理器
    }
    
    #lsx 获取OAuth管理器实例
    @classmethod
    def get_manager(cls, oauth_type):
        #lsx 根据类型返回对应的OAuth管理器
        manager_class = cls.managers.get(oauth_type)
        if manager_class:
            return manager_class()
        return None
    
    #lsx 获取授权URL
    @classmethod
    def get_authorization_url(cls, oauth_type):
        #lsx 获取授权URL
        manager = cls.get_manager(oauth_type)
        if manager:
            return manager.get_authorization_url()
        return None
    
    #lsx 处理回调
    @classmethod
    def callback(cls, request, oauth_type):
        #lsx 处理OAuth回调
        manager = cls.get_manager(oauth_type)
        if manager:
            manager.request = request
            return manager.callback(request)
        return JsonResponse({'status': 'fail', 'msg': _('不支持的OAuth类型')})