from django.views.generic import DetailView, TemplateView
from django.contrib.auth import get_user_model, login, authenticate
from django.shortcuts import get_object_or_404, redirect, render
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
from allauth.socialaccount.providers.discord.views import DiscordOAuth2Adapter
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from django.conf import settings
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.crypto import get_random_string
from django.utils import timezone
from datetime import timedelta
from django.contrib.sites.shortcuts import get_current_site
from django.db.models import Prefetch
from django.http import HttpResponseRedirect
from django.urls import reverse
from accounts.models import User, PasswordReset
from reviews.models import Review
from email_service.services import EmailService

User = get_user_model()

@login_required
def user_redirect_view(request):
    """Redirect /user/ to the logged-in user's profile"""
    return redirect('profile', username=request.user.username)

def email_required(request):
    """Handle cases where social auth provider doesn't provide an email"""
    sociallogin = request.session.get('socialaccount_sociallogin')
    if not sociallogin:
        messages.error(request, 'No social login in progress')
        return redirect('/')

    if request.method == 'POST':
        email = request.POST.get('email')
        if email:
            sociallogin.user.email = email
            sociallogin.save()
            login(request, sociallogin.user)
            del request.session['socialaccount_sociallogin']
            messages.success(request, 'Successfully logged in')
            return redirect('/')
        else:
            messages.error(request, 'Email is required')
            return render(request, 'accounts/email_required.html', {'error': 'Email is required'})

    return render(request, 'accounts/email_required.html')

class ProfileView(DetailView):
    model = User
    template_name = 'accounts/profile.html'
    context_object_name = 'profile_user'
    slug_field = 'username'
    slug_url_kwarg = 'username'

    def get_queryset(self):
        # Optimize the base queryset with select_related
        return User.objects.select_related('profile')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        user = self.get_object()
        
        # Get user's reviews with optimized queries
        reviews_queryset = Review.objects.filter(
            user=user,
            is_published=True
        ).select_related(
            'user',
            'user__profile',
            'content_type'
        ).prefetch_related(
            'content_object'  # This will fetch the related ride/park/etc.
        ).order_by('-created_at')[:5]
        
        context['recent_reviews'] = reviews_queryset
        
        # Get user's top lists with optimized queries
        context['top_lists'] = user.top_lists.select_related(
            'user',
            'user__profile'
        ).prefetch_related(
            Prefetch('items', queryset=(
                user.top_lists.through.objects.select_related(
                    'content_type'
                ).prefetch_related('content_object')
            ))
        ).order_by('-created_at')[:5]
        
        return context

class SettingsView(LoginRequiredMixin, TemplateView):
    template_name = 'accounts/settings.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['user'] = self.request.user
        return context

    def post(self, request, *args, **kwargs):
        action = request.POST.get('action')
        
        if action == 'update_profile':
            # Handle profile updates
            user = request.user
            user.first_name = request.POST.get('first_name', user.first_name)
            user.last_name = request.POST.get('last_name', user.last_name)
            
            if 'avatar' in request.FILES:
                user.profile.avatar = request.FILES['avatar']
                user.profile.save()
            
            user.save()
            messages.success(request, 'Profile updated successfully')
        
        elif action == 'change_password':
            # Handle password change
            old_password = request.POST.get('old_password')
            new_password = request.POST.get('new_password')
            
            if request.user.check_password(old_password):
                request.user.set_password(new_password)
                request.user.save()
                messages.success(request, 'Password changed successfully')
                return HttpResponseRedirect(reverse('account_login'))
            else:
                messages.error(request, 'Current password is incorrect')
        
        return self.get(request, *args, **kwargs)

def request_password_reset(request):
    """Request a password reset email"""
    if request.method == 'POST':
        email = request.POST.get('email')
        if not email:
            messages.error(request, 'Email is required')
            return redirect('account_reset_password')
        
        try:
            user = User.objects.get(email=email)
            # Generate token
            token = get_random_string(64)
            # Save token with expiry
            PasswordReset.objects.update_or_create(
                user=user,
                defaults={
                    'token': token,
                    'expires_at': timezone.now() + timedelta(hours=24)
                }
            )
            
            # Get current site
            site = get_current_site(request)
            
            # Send reset email
            reset_url = reverse('password_reset_confirm', kwargs={'token': token})
            context = {
                'user': user,
                'reset_url': reset_url,
                'site_name': site.name,
            }
            email_html = render_to_string('accounts/email/password_reset.html', context)
            
            # Use EmailService instead of send_mail
            EmailService.send_email(
                to=email,
                subject='Reset your password',
                text='Click the link to reset your password',
                site=site,
                html=email_html
            )
            
            messages.success(request, 'Password reset email sent')
            return redirect('account_login')
        except User.DoesNotExist:
            # Still show success to prevent email enumeration
            messages.success(request, 'Password reset email sent')
            return redirect('account_login')
    
    return render(request, 'accounts/password_reset.html')

def reset_password(request, token):
    """Reset password using token"""
    try:
        # Get valid reset token
        reset = PasswordReset.objects.select_related('user').get(
            token=token,
            expires_at__gt=timezone.now(),
            used=False
        )
        
        if request.method == 'POST':
            new_password = request.POST.get('new_password')
            if new_password:
                # Reset password
                user = reset.user
                user.set_password(new_password)
                user.save()
                
                # Mark token as used
                reset.used = True
                reset.save()
                
                # Get current site
                site = get_current_site(request)
                
                # Send confirmation email
                context = {
                    'user': user,
                    'site_name': site.name,
                }
                email_html = render_to_string('accounts/email/password_reset_complete.html', context)
                
                # Use EmailService instead of send_mail
                EmailService.send_email(
                    to=user.email,
                    subject='Password Reset Complete',
                    text='Your password has been reset successfully.',
                    site=site,
                    html=email_html
                )
                
                messages.success(request, 'Password reset successfully')
                return redirect('account_login')
            else:
                messages.error(request, 'New password is required')
        
        return render(request, 'accounts/password_reset_confirm.html', {'token': token})
    except PasswordReset.DoesNotExist:
        messages.error(request, 'Invalid or expired reset token')
        return redirect('account_reset_password')
