from rest_framework import status, generics, permissions
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken
from django.contrib.auth import authenticate
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from django.conf import settings
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django_ratelimit.decorators import ratelimit
from decouple import config
from .models import User, PasswordResetToken, VerificationCode
from .serializers import (
    UserSerializer,
    UserRegistrationSerializer,
    UserProfileSerializer,
    ChangePasswordSerializer,
    PasswordResetSerializer,
    PasswordResetConfirmSerializer,
    EmailVerificationSerializer,
    EmailVerificationConfirmSerializer,
    PhoneVerificationSerializer,
    PhoneVerificationConfirmSerializer,
    GoogleLoginSerializer,
)


@api_view(['POST'])
@permission_classes([permissions.AllowAny])
@ratelimit(key='ip', rate='5/m', method='POST')
def register(request):
    """User Registration"""
    # Ensure username is email if not provided
    data = request.data.copy()
    if 'username' not in data or not data.get('username'):
        email = data.get('email', '')
        if email:
            data['username'] = email.split('@')[0]
    
    serializer = UserRegistrationSerializer(data=data)
    if serializer.is_valid():
        user = serializer.save()
        refresh = RefreshToken.for_user(user)
        return Response({
            'user': UserSerializer(user).data,
            'refresh': str(refresh),
            'access': str(refresh.access_token),
        }, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['POST'])
@permission_classes([permissions.AllowAny])
@ratelimit(key='ip', rate='10/m', method='POST')
def login(request):
    """User Login - accepts username or email"""
    username_or_email = request.data.get('username')
    password = request.data.get('password')

    if not username_or_email or not password:
        return Response(
            {'error': 'اسم المستخدم أو البريد الإلكتروني وكلمة المرور مطلوبة'},
            status=status.HTTP_400_BAD_REQUEST
        )

    # Try to find user by username first, then by email
    user = None
    if '@' in username_or_email:
        # Looks like an email
        try:
            user_obj = User.objects.get(email=username_or_email)
            user = authenticate(username=user_obj.username, password=password)
        except User.DoesNotExist:
            pass
    else:
        # Looks like a username
        user = authenticate(username=username_or_email, password=password)

    # If still not found, try both
    if user is None and '@' not in username_or_email:
        try:
            user_obj = User.objects.get(email=username_or_email)
            user = authenticate(username=user_obj.username, password=password)
        except User.DoesNotExist:
            pass

    if user is None:
        return Response(
            {'error': 'اسم المستخدم أو البريد الإلكتروني أو كلمة المرور غير صحيحة'},
            status=status.HTTP_401_UNAUTHORIZED
        )

    if not user.is_active:
        return Response(
            {'error': 'حساب المستخدم معطل'},
            status=status.HTTP_401_UNAUTHORIZED
        )

    refresh = RefreshToken.for_user(user)
    return Response({
        'user': UserSerializer(user).data,
        'refresh': str(refresh),
        'access': str(refresh.access_token),
    })


@api_view(['POST'])
@permission_classes([permissions.AllowAny])
def token_refresh(request):
    """Refresh JWT Token"""
    refresh_token = request.data.get('refresh')
    if not refresh_token:
        return Response(
            {'error': 'Refresh token is required'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    try:
        refresh = RefreshToken(refresh_token)
        return Response({
            'access': str(refresh.access_token),
        })
    except Exception as e:
        return Response(
            {'error': 'Invalid or expired refresh token'},
            status=status.HTTP_401_UNAUTHORIZED
        )


@api_view(['POST'])
@permission_classes([permissions.IsAuthenticated])
def logout(request):
    """User Logout"""
    try:
        refresh_token = request.data.get('refresh')
        if refresh_token:
            token = RefreshToken(refresh_token)
            token.blacklist()
        return Response({'message': 'Successfully logged out'}, status=status.HTTP_200_OK)
    except Exception as e:
        return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST)


@api_view(['GET', 'PATCH'])
@permission_classes([permissions.IsAuthenticated])
def profile(request):
    """Get or Update User Profile"""
    if request.method == 'GET':
        serializer = UserProfileSerializer(request.user)
        return Response(serializer.data)
    
    elif request.method == 'PATCH':
        serializer = UserProfileSerializer(request.user, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['POST'])
@permission_classes([permissions.IsAuthenticated])
def change_password(request):
    """Change User Password"""
    serializer = ChangePasswordSerializer(data=request.data)
    if serializer.is_valid():
        user = request.user
        if not user.check_password(serializer.validated_data['old_password']):
            return Response(
                {'error': 'Wrong password'},
                status=status.HTTP_400_BAD_REQUEST
            )
        user.set_password(serializer.validated_data['new_password'])
        user.save()
        return Response({'message': 'Password changed successfully'})
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['POST'])
@permission_classes([permissions.IsAuthenticated])
def upload_avatar(request):
    """Upload User Avatar"""
    if 'avatar' not in request.FILES:
        return Response(
            {'error': 'No avatar file provided'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    from common.utils import save_image
    from django.conf import settings
    
    try:
        user = request.user
        image_file = request.FILES['avatar']
        image_path = f'avatars/{user.id}/{image_file.name}'
        saved_path = save_image(image_file, image_path, optimize=True)
        
        user.avatar = saved_path
        user.save(update_fields=['avatar'])
        
        return Response({
            'message': 'Avatar uploaded successfully',
            'avatar_url': user.avatar.url if user.avatar else None
        })
    except ValueError as e:
        return Response(
            {'error': str(e)},
            status=status.HTTP_400_BAD_REQUEST
        )
    except Exception as e:
        return Response(
            {'error': 'Failed to upload avatar'},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )


@api_view(['POST'])
@permission_classes([permissions.IsAuthenticated])
def delete_account(request):
    """Delete User Account (Soft Delete)"""
    password = request.data.get('password')
    
    if not password:
        return Response(
            {'error': 'كلمة المرور مطلوبة'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    user = request.user
    
    # Verify password
    if not user.check_password(password):
        return Response(
            {'error': 'كلمة المرور غير صحيحة'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    # Soft delete: deactivate account instead of deleting
    user.is_active = False
    user.save(update_fields=['is_active'])
    
    # Logout user by blacklisting tokens
    try:
        refresh_token = RefreshToken.for_user(user)
        refresh_token.blacklist()
    except Exception:
        pass
    
    return Response({
        'message': 'تم حذف الحساب بنجاح'
    }, status=status.HTTP_200_OK)


@api_view(['PATCH'])
@permission_classes([permissions.IsAuthenticated])
def update_settings(request):
    """Update User Settings (notifications, language, theme)"""
    user = request.user
    allowed_fields = ['notifications_enabled', 'language', 'theme']
    
    # Filter only allowed fields
    data = {k: v for k, v in request.data.items() if k in allowed_fields}
    
    if not data:
        return Response(
            {'error': 'لا توجد بيانات للتحديث'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    # Update user settings
    for field, value in data.items():
        if hasattr(user, field):
            setattr(user, field, value)
    
    user.save(update_fields=data.keys())
    
    serializer = UserProfileSerializer(user)
    return Response(serializer.data, status=status.HTTP_200_OK)


@api_view(['POST'])
@permission_classes([permissions.AllowAny])
@ratelimit(key='ip', rate='3/h', method='POST')
def password_reset(request):
    """Request Password Reset"""
    serializer = PasswordResetSerializer(data=request.data)
    if not serializer.is_valid():
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    email = serializer.validated_data['email']
    try:
        user = User.objects.get(email=email, is_active=True)
    except User.DoesNotExist:
        # Don't reveal if email exists or not
        return Response(
            {'message': 'If the email exists, a password reset link has been sent.'},
            status=status.HTTP_200_OK
        )
    
    # Generate reset token
    reset_token = PasswordResetToken.generate_token(user)
    
    # Send email (in production, use Celery task)
    reset_url = f"{settings.FRONTEND_URL or 'http://localhost:3000'}/reset-password?token={reset_token.token}"
    try:
        send_mail(
            subject='Password Reset Request - Daleeli IQ',
            message=f'Click the following link to reset your password: {reset_url}',
            from_email=settings.DEFAULT_FROM_EMAIL,
            recipient_list=[user.email],
            fail_silently=False,
        )
    except Exception as e:
        # Log error but don't reveal to user
        print(f'Error sending password reset email: {e}')
    
    return Response(
        {'message': 'If the email exists, a password reset link has been sent.'},
        status=status.HTTP_200_OK
    )


@api_view(['POST'])
@permission_classes([permissions.AllowAny])
def password_reset_confirm(request):
    """Confirm Password Reset"""
    serializer = PasswordResetConfirmSerializer(data=request.data)
    if not serializer.is_valid():
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    token_str = serializer.validated_data['token']
    new_password = serializer.validated_data['new_password']
    
    try:
        reset_token = PasswordResetToken.objects.get(token=token_str, used=False)
    except PasswordResetToken.DoesNotExist:
        return Response(
            {'error': 'Invalid or expired reset token'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    if not reset_token.is_valid():
        return Response(
            {'error': 'Reset token has expired'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    # Reset password
    user = reset_token.user
    user.set_password(new_password)
    user.save()
    
    # Mark token as used
    reset_token.used = True
    reset_token.save()
    
    return Response({'message': 'Password has been reset successfully'})


@api_view(['POST'])
@permission_classes([permissions.AllowAny])
@ratelimit(key='ip', rate='5/h', method='POST')
def email_verification(request):
    """Request Email Verification"""
    serializer = EmailVerificationSerializer(data=request.data)
    if not serializer.is_valid():
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    email = serializer.validated_data['email']
    try:
        user = User.objects.get(email=email)
    except User.DoesNotExist:
        return Response(
            {'error': 'User with this email does not exist'},
            status=status.HTTP_404_NOT_FOUND
        )
    
    if user.email_verified:
        return Response(
            {'message': 'Email is already verified'},
            status=status.HTTP_200_OK
        )
    
    # Generate verification code
    verification_code = VerificationCode.generate_code(user, 'email')
    
    # Send email (in production, use Celery task)
    try:
        send_mail(
            subject='Email Verification - Daleeli IQ',
            message=f'Your verification code is: {verification_code.code}',
            from_email=settings.DEFAULT_FROM_EMAIL,
            recipient_list=[user.email],
            fail_silently=False,
        )
    except Exception as e:
        print(f'Error sending verification email: {e}')
        return Response(
            {'error': 'Failed to send verification email'},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )
    
    return Response(
        {'message': 'Verification code has been sent to your email'},
        status=status.HTTP_200_OK
    )


@api_view(['POST'])
@permission_classes([permissions.AllowAny])
def email_verification_confirm(request):
    """Confirm Email Verification"""
    serializer = EmailVerificationConfirmSerializer(data=request.data)
    if not serializer.is_valid():
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    email = serializer.validated_data['email']
    code = serializer.validated_data['code']
    
    try:
        user = User.objects.get(email=email)
    except User.DoesNotExist:
        return Response(
            {'error': 'User with this email does not exist'},
            status=status.HTTP_404_NOT_FOUND
        )
    
    try:
        verification_code = VerificationCode.objects.filter(
            user=user,
            type='email',
            code=code,
            used=False
        ).latest('created_at')
    except VerificationCode.DoesNotExist:
        return Response(
            {'error': 'Invalid verification code'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    if not verification_code.is_valid():
        return Response(
            {'error': 'Verification code has expired'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    # Mark email as verified
    user.email_verified = True
    user.save()
    
    # Mark code as used
    verification_code.used = True
    verification_code.save()
    
    return Response({'message': 'Email verified successfully'})


@api_view(['POST'])
@permission_classes([permissions.AllowAny])
@ratelimit(key='ip', rate='5/h', method='POST')
def phone_verification(request):
    """Request Phone Verification"""
    serializer = PhoneVerificationSerializer(data=request.data)
    if not serializer.is_valid():
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    phone = serializer.validated_data['phone']
    try:
        user = User.objects.get(phone=phone)
    except User.DoesNotExist:
        return Response(
            {'error': 'User with this phone does not exist'},
            status=status.HTTP_404_NOT_FOUND
        )
    
    if user.phone_verified:
        return Response(
            {'message': 'Phone is already verified'},
            status=status.HTTP_200_OK
        )
    
    # Generate verification code
    verification_code = VerificationCode.generate_code(user, 'phone')
    
    # Send SMS (in production, use SMS service like Twilio)
    # For now, just return the code in development
    if settings.DEBUG:
        return Response(
            {
                'message': 'Verification code sent (DEBUG MODE)',
                'code': verification_code.code  # Only in DEBUG
            },
            status=status.HTTP_200_OK
        )
    
    # TODO: Integrate with SMS service
    return Response(
        {'message': 'Verification code has been sent to your phone'},
        status=status.HTTP_200_OK
    )


@api_view(['POST'])
@permission_classes([permissions.AllowAny])
def phone_verification_confirm(request):
    """Confirm Phone Verification"""
    serializer = PhoneVerificationConfirmSerializer(data=request.data)
    if not serializer.is_valid():
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    phone = serializer.validated_data['phone']
    code = serializer.validated_data['code']
    
    try:
        user = User.objects.get(phone=phone)
    except User.DoesNotExist:
        return Response(
            {'error': 'User with this phone does not exist'},
            status=status.HTTP_404_NOT_FOUND
        )
    
    try:
        verification_code = VerificationCode.objects.filter(
            user=user,
            type='phone',
            code=code,
            used=False
        ).latest('created_at')
    except VerificationCode.DoesNotExist:
        return Response(
            {'error': 'Invalid verification code'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    if not verification_code.is_valid():
        return Response(
            {'error': 'Verification code has expired'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    # Mark phone as verified
    user.phone_verified = True
    user.save()
    
    # Mark code as used
    verification_code.used = True
    verification_code.save()
    
    return Response({'message': 'Phone verified successfully'})


@api_view(['POST'])
@permission_classes([permissions.AllowAny])
@ratelimit(key='ip', rate='10/m', method='POST')
def google_login(request):
    """Google OAuth Login"""
    serializer = GoogleLoginSerializer(data=request.data)
    if not serializer.is_valid():
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    id_token_str = serializer.validated_data['id_token']
    
    try:
        # Import Google auth libraries
        from google.oauth2 import id_token
        from google.auth.transport import requests as google_requests
        
        # Get Google Client ID from settings
        GOOGLE_CLIENT_ID = config('GOOGLE_CLIENT_ID', default='')
        
        if not GOOGLE_CLIENT_ID:
            return Response(
                {'error': 'Google OAuth not configured. Please set GOOGLE_CLIENT_ID in environment variables.'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        
        # Verify the token
        try:
            idinfo = id_token.verify_oauth2_token(
                id_token_str,
                google_requests.Request(),
                GOOGLE_CLIENT_ID
            )
        except ValueError as e:
            return Response(
                {'error': f'Invalid token: {str(e)}'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # Get user info from token
        email = idinfo.get('email')
        name = idinfo.get('name', '')
        picture = idinfo.get('picture')
        google_id = idinfo.get('sub')
        
        if not email or not google_id:
            return Response(
                {'error': 'Invalid token: missing email or user ID'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # Find or create user
        user = None
        created = False
        
        # Try to find user by social_id first
        try:
            user = User.objects.get(social_id=google_id, social_provider='google')
        except User.DoesNotExist:
            # Try to find by email
            try:
                user = User.objects.get(email=email)
                # Update existing user with social info
                user.social_provider = 'google'
                user.social_id = google_id
                user.email_verified = True
                if not user.is_verified:
                    user.is_verified = True
                user.save()
            except User.DoesNotExist:
                # Create new user
                username = email.split('@')[0]
                # Ensure username is unique
                base_username = username
                counter = 1
                while User.objects.filter(username=username).exists():
                    username = f"{base_username}{counter}"
                    counter += 1
                
                # Split name into first and last
                name_parts = name.split() if name else []
                first_name = name_parts[0] if name_parts else ''
                last_name = ' '.join(name_parts[1:]) if len(name_parts) > 1 else ''
                
                user = User.objects.create_user(
                    username=username,
                    email=email,
                    first_name=first_name,
                    last_name=last_name,
                    social_provider='google',
                    social_id=google_id,
                    email_verified=True,
                    is_verified=True,
                )
                created = True
        
        # Generate JWT tokens
        refresh = RefreshToken.for_user(user)
        return Response({
            'user': UserSerializer(user).data,
            'refresh': str(refresh),
            'access': str(refresh.access_token),
        }, status=status.HTTP_200_OK)
        
    except ImportError:
        return Response(
            {'error': 'Google auth libraries not installed. Install with: pip install google-auth google-auth-oauthlib google-auth-httplib2'},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )
    except Exception as e:
        return Response(
            {'error': f'An error occurred: {str(e)}'},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )
