"""
用户模块视图 - App端用户
"""
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework_simplejwt.tokens import RefreshToken
from django.db.models import Count
from drf_spectacular.utils import extend_schema

from django.utils import timezone
from utils.response import success, error
from utils.exceptions import ErrorCode
from utils.sms import send_sms_code, verify_sms_code
from utils.phone_auth import get_phone_auth_client
from utils.oss import get_oss_client
from apps.admins.authentication import AppJWTAuthentication, AdminJWTAuthentication
from apps.admins.permissions import IsAdminUser
from .models import User
from .serializers import (
    UserSerializer,
    UserDetailSerializer,
    PhoneLoginSerializer,
    UpdateUserSerializer,
    SendCodeSerializer,
    CodeLoginSerializer,
    PointsRecordSerializer,
)
from .models import PointsRecord


def get_app_tokens(user):
    """
    为App用户生成JWT Token
    在token中添加 user_type='app' 以区分管理员
    """
    refresh = RefreshToken.for_user(user)
    # 添加自定义声明
    refresh['user_type'] = 'app'
    refresh['phone'] = user.phone
    
    return {
        'access': str(refresh.access_token),
        'refresh': str(refresh),
    }


@extend_schema(tags=['认证'])
class AuthViewSet(viewsets.ViewSet):
    """认证视图集 - App端"""
    
    permission_classes = [AllowAny]
    
    @action(detail=False, methods=['post'], url_path='phone-login')
    def phone_login(self, request):
        """
        手机号一键登录（阿里云号码认证）
        POST /api/v1/auth/phone-login
        App 端通过阿里云 SDK 获取 token，后端用 token 换取真实手机号
        """
        serializer = PhoneLoginSerializer(data=request.data)
        if not serializer.is_valid():
            return error(message=str(serializer.errors))

        access_token = serializer.validated_data['token']

        # 用 token 换取真实手机号
        client = get_phone_auth_client()
        phone, err = client.get_mobile(access_token)
        if not phone:
            return error(code=102, message=err or '号码认证失败')

        # 获取或创建用户
        user, created = User.objects.get_or_create(
            phone=phone,
            defaults={'nickname': f'用户{phone[-4:]}'}
        )

        if not user.is_active:
            return error(code=101, message='账号已被禁用')

        # 生成JWT Token（带user_type='app'标识）
        tokens = get_app_tokens(user)

        return success(data={
            'user': UserSerializer(user).data,
            'token': tokens,
            'is_new_user': created
        }, message='登录成功')
    
    @action(detail=False, methods=['post'], url_path='send-code')
    def send_code(self, request):
        """
        发送验证码
        POST /api/v1/auth/send-code/
        """
        serializer = SendCodeSerializer(data=request.data)
        if not serializer.is_valid():
            return error(message=str(serializer.errors))

        phone = serializer.validated_data['phone']
        ok, err = send_sms_code(phone)
        if not ok:
            return error(code=ErrorCode.SMS_CODE_SEND_LIMIT, message=err)

        return success(
            data={'expire_in': 60},
            message='验证码已发送'
        )

    @action(detail=False, methods=['post'], url_path='code-login')
    def code_login(self, request):
        """
        验证码登录
        POST /api/v1/auth/code-login/
        """
        serializer = CodeLoginSerializer(data=request.data)
        if not serializer.is_valid():
            return error(message=str(serializer.errors))

        phone = serializer.validated_data['phone']
        code = serializer.validated_data['code']

        # 校验验证码
        valid, err = verify_sms_code(phone, code)
        if not valid:
            return error(code=ErrorCode.SMS_CODE_INVALID, message=err)

        # 获取或创建用户
        user, created = User.objects.get_or_create(
            phone=phone,
            defaults={'nickname': f'用户{phone[-4:]}'}
        )

        if not user.is_active:
            return error(code=ErrorCode.USER_DISABLED, message='账号已被禁用')

        tokens = get_app_tokens(user)

        return success(data={
            'user': UserSerializer(user).data,
            'token': tokens,
            'is_new_user': created
        }, message='登录成功')

    @action(detail=False, methods=['post'], url_path='logout',
            authentication_classes=[AppJWTAuthentication],
            permission_classes=[IsAuthenticated])
    def logout(self, request):
        """
        退出登录
        POST /api/v1/auth/logout/
        """
        try:
            refresh_token = request.data.get('refresh')
            if refresh_token:
                token = RefreshToken(refresh_token)
                token.blacklist()
        except Exception:
            pass
        return success(message='已退出登录')

    @action(detail=False, methods=['delete'], url_path='account',
            authentication_classes=[AppJWTAuthentication],
            permission_classes=[IsAuthenticated])
    def delete_account(self, request):
        """
        账号注销
        DELETE /api/v1/auth/account/
        """
        user = request.user
        user.is_pending_deletion = True
        user.deletion_requested_at = timezone.now()
        user.save(update_fields=['is_pending_deletion', 'deletion_requested_at'])
        return success(message='账号注销申请已提交，将在7个工作日内处理')

    @action(detail=False, methods=['post'], url_path='refresh')
    def refresh_token(self, request):
        """
        刷新Token
        POST /api/v1/auth/refresh
        """
        refresh_token = request.data.get('refresh')
        if not refresh_token:
            return error(message='refresh token不能为空')
        
        try:
            refresh = RefreshToken(refresh_token)
            # 验证是否为app token
            user_type = refresh.get('user_type', 'app')
            if user_type not in ['app', None]:
                return error(code=103, message='无效的用户Token')
            
            return success(data={
                'access': str(refresh.access_token),
                'refresh': str(refresh),
            })
        except Exception as e:
            return error(code=103, message='Token已过期或无效')


@extend_schema(tags=['用户'])
class UserViewSet(viewsets.ViewSet):
    """用户视图集 - App端"""
    
    authentication_classes = [AppJWTAuthentication]
    permission_classes = [IsAuthenticated]
    
    @action(detail=False, methods=['get'])
    def me(self, request):
        """
        获取当前用户信息
        GET /api/v1/users/me
        """
        return success(data=UserSerializer(request.user).data)
    
    @action(detail=False, methods=['put'])
    def update_me(self, request):
        """
        更新当前用户信息
        PUT /api/v1/users/update_me
        """
        serializer = UpdateUserSerializer(request.user, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return success(data=UserSerializer(request.user).data, message='更新成功')
        return error(message=str(serializer.errors))

    @action(detail=False, methods=['post'])
    def avatar(self, request):
        """
        上传头像
        POST /api/v1/users/avatar/
        """
        file = request.FILES.get('file')
        if not file:
            return error(message='请选择文件')

        # 验证文件类型
        allowed_types = ['image/jpeg', 'image/png', 'image/gif']
        if file.content_type not in allowed_types:
            return error(message='仅支持 JPG、PNG、GIF 格式')

        # 验证文件大小 (5MB)
        if file.size > 5 * 1024 * 1024:
            return error(message='文件大小不能超过 5MB')

        try:
            oss_client = get_oss_client()
            avatar_url = oss_client.upload_file(file, folder='avatars')
        except Exception as e:
            return error(message=f'上传失败: {str(e)}')

        request.user.avatar = avatar_url
        request.user.save(update_fields=['avatar'])

        return success(data={'avatar_url': avatar_url})

    @action(detail=False, methods=['get'])
    def points(self, request):
        """
        查询积分余额
        GET /api/v1/users/points/
        """
        return success(data={'points': request.user.points})

    @action(detail=False, methods=['get'], url_path='points/records')
    def points_records(self, request):
        """
        积分流水记录
        GET /api/v1/users/points/records/?page=1&page_size=20
        """
        queryset = PointsRecord.objects.filter(user=request.user)

        page = int(request.query_params.get('page', 1))
        page_size = int(request.query_params.get('page_size', 20))
        start = (page - 1) * page_size
        total = queryset.count()
        items = queryset[start:start + page_size]

        return success(data={
            'total': total,
            'items': PointsRecordSerializer(items, many=True).data,
        })


@extend_schema(tags=['管理员-用户管理'])
class AdminUserManageViewSet(viewsets.ViewSet):
    """App用户管理视图集 - 管理端"""
    
    authentication_classes = [AdminJWTAuthentication]
    permission_classes = [IsAdminUser]
    
    def list(self, request):
        """
        用户列表
        GET /api/admin/users
        """
        queryset = User.objects.all().order_by('-created_at')
        
        # 搜索条件
        phone = request.query_params.get('phone')
        nickname = request.query_params.get('nickname')
        is_active = request.query_params.get('is_active')
        
        if phone:
            queryset = queryset.filter(phone__contains=phone)
        if nickname:
            queryset = queryset.filter(nickname__contains=nickname)
        if is_active is not None:
            queryset = queryset.filter(is_active=(is_active.lower() == 'true'))
        
        # 标注统计数据
        queryset = queryset.annotate(
            spirit_count=Count('spirits', distinct=True),
            device_count=Count('user_devices', distinct=True)
        )
        
        # 分页
        page = int(request.query_params.get('page', 1))
        page_size = int(request.query_params.get('page_size', 10))
        start = (page - 1) * page_size
        end = start + page_size
        
        total = queryset.count()
        users = queryset[start:end]
        
        # 手动构造带统计的数据
        items = []
        for user in users:
            data = UserSerializer(user).data
            data['spirit_count'] = getattr(user, 'spirit_count', 0)
            data['device_count'] = getattr(user, 'device_count', 0)
            items.append(data)
        
        return success(data={
            'total': total,
            'items': items
        })
    
    def retrieve(self, request, pk=None):
        """
        用户详情
        GET /api/admin/users/{id}
        """
        try:
            user = User.objects.get(pk=pk)
        except User.DoesNotExist:
            return error(message='用户不存在')
        
        data = UserDetailSerializer(user).data
        data['spirit_count'] = user.spirits.count()
        data['device_count'] = user.user_devices.count()
        
        return success(data=data)
    
    @action(detail=True, methods=['post'], url_path='toggle-status')
    def toggle_status(self, request, pk=None):
        """
        启用/禁用用户
        POST /api/admin/users/{id}/toggle-status
        """
        try:
            user = User.objects.get(pk=pk)
        except User.DoesNotExist:
            return error(message='用户不存在')
        
        user.is_active = not user.is_active
        user.save()
        
        return success(
            data=UserSerializer(user).data,
            message='已启用' if user.is_active else '已禁用'
        )

