"""
Views for the accounts app.
Handles: login, logout, signup, profile.
"""
from django.views.generic import CreateView, UpdateView, TemplateView
from django.views import View
from django.contrib.auth.views import LoginView, LogoutView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.urls import reverse_lazy, reverse
from django.shortcuts import render, redirect
from django.contrib.auth.tokens import default_token_generator
from django.utils.encoding import force_bytes, force_str
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.conf import settings as django_settings
from apps.accounts.forms import (
    StudentSignupForm, TeacherSignupForm, CustomLoginForm, ProfileUpdateForm,
    ForgotPasswordForm, SetNewPasswordForm, ChangePasswordForm,
)
from apps.accounts.models import CustomUser
from django.contrib.auth import update_session_auth_hash


class CustomLoginView(LoginView):
    """Custom login view with Bootstrap-styled form."""
    form_class = CustomLoginForm
    template_name = 'accounts/login.html'

    def form_valid(self, form):
        messages.success(self.request, f"Welcome back, {form.get_user().get_display_name()}!")
        return super().form_valid(form)

    def get_success_url(self):
        return reverse_lazy('dashboard:redirect')


class StudentSignupView(CreateView):
    """View for student registration."""
    model = CustomUser
    form_class = StudentSignupForm
    template_name = 'accounts/student_signup.html'
    success_url = reverse_lazy('accounts:login')

    def form_valid(self, form):
        response = super().form_valid(form)
        try:
            from apps.dashboard.email_service import send_signup_emails
            send_signup_emails(self.object, request=self.request)
        except Exception:
            pass  # signup must succeed even if email fails
        messages.success(self.request, "Student account created successfully! Please log in.")
        return response

    def dispatch(self, request, *args, **kwargs):
        if request.user.is_authenticated:
            return redirect_to_dashboard(request)
        return super().dispatch(request, *args, **kwargs)


class TeacherSignupView(CreateView):
    """View for teacher registration."""
    model = CustomUser
    form_class = TeacherSignupForm
    template_name = 'accounts/teacher_signup.html'
    success_url = reverse_lazy('accounts:login')

    def form_valid(self, form):
        response = super().form_valid(form)
        try:
            from apps.dashboard.email_service import send_signup_emails
            send_signup_emails(self.object, request=self.request)
        except Exception:
            pass
        messages.success(self.request, "Teacher account created successfully! Please log in.")
        return response

    def dispatch(self, request, *args, **kwargs):
        if request.user.is_authenticated:
            return redirect_to_dashboard(request)
        return super().dispatch(request, *args, **kwargs)


class ProfileView(LoginRequiredMixin, UpdateView):
    """View for viewing and updating user profile."""
    model = CustomUser
    form_class = ProfileUpdateForm
    template_name = 'accounts/profile.html'
    success_url = reverse_lazy('accounts:profile')

    def get_object(self):
        return self.request.user

    def form_valid(self, form):
        messages.success(self.request, "Profile updated successfully!")
        return super().form_valid(form)


class ChangePasswordView(LoginRequiredMixin, View):
    """Logged-in user changes their own password from My Profile."""
    template_name = 'accounts/change_password.html'

    def get(self, request):
        return render(request, self.template_name, {
            'form': ChangePasswordForm(user=request.user),
        })

    def post(self, request):
        form = ChangePasswordForm(user=request.user, data=request.POST)
        if form.is_valid():
            form.save()
            update_session_auth_hash(request, request.user)
            messages.success(request, 'Your password has been updated successfully.')
            return redirect('accounts:profile')
        return render(request, self.template_name, {'form': form})


def redirect_to_dashboard(request):
    """Helper to redirect authenticated users to their dashboard."""
    return redirect('dashboard:redirect')


class ForgotPasswordView(View):
    """
    Step 1: verify identity via email + CNIC.
    On success, sends a time-limited password-reset link to the user's email.
    The link is built with Django's PasswordResetTokenGenerator so it
    auto-invalidates once used or when the password changes.
    """
    template_name = 'accounts/forgot_password.html'

    # Expiry in hours shown in the email (must match PASSWORD_RESET_TIMEOUT in settings)
    EXPIRY_HOURS = int(getattr(django_settings, 'PASSWORD_RESET_TIMEOUT', 259200)) // 3600

    def get(self, request):
        if request.user.is_authenticated:
            return redirect_to_dashboard(request)
        return render(request, self.template_name, {'form': ForgotPasswordForm()})

    def post(self, request):
        form = ForgotPasswordForm(request.POST)
        if form.is_valid():
            email = form.cleaned_data['email'].strip().lower()
            cnic  = form.cleaned_data['cnic']           # already digits-only from clean_cnic
            try:
                user = CustomUser.objects.get(email__iexact=email, cnic=cnic)
            except CustomUser.DoesNotExist:
                # Generic error — avoids leaking which field was wrong (user enumeration)
                form.add_error(None, 'No account found with that email and CNIC combination.')
                return render(request, self.template_name, {'form': form})

            # Build the reset URL
            uid   = urlsafe_base64_encode(force_bytes(user.pk))
            token = default_token_generator.make_token(user)
            reset_path = reverse('accounts:reset_password', kwargs={'uidb64': uid, 'token': token})
            reset_url  = request.build_absolute_uri(reset_path)

            from apps.dashboard.email_service import send_password_reset_email
            send_password_reset_email(
                user,
                reset_url=reset_url,
                expiry_hours=self.EXPIRY_HOURS,
                request=request,
            )

            # Show "check your email" confirmation — do NOT redirect to the reset URL directly
            # (that would skip the email step entirely)
            return render(request, self.template_name, {
                'form':         None,
                'email_sent':   True,
                'masked_email': self._mask_email(user.email),
            })

        return render(request, self.template_name, {'form': form})

    @staticmethod
    def _mask_email(email):
        """Return e.g. 'ab****@example.com' so we don't expose the full address in the page."""
        local, domain = email.rsplit('@', 1)
        visible = local[:2] if len(local) > 2 else local[:1]
        return f"{visible}{'*' * (len(local) - len(visible))}@{domain}"


class ResetPasswordView(View):
    """
    Step 2: user sets a new password.
    The uidb64/token URL is valid only once and expires after PASSWORD_RESET_TIMEOUT seconds.
    """
    template_name = 'accounts/reset_password.html'

    def _get_user(self, uidb64):
        try:
            uid = force_str(urlsafe_base64_decode(uidb64))
            return CustomUser.objects.get(pk=uid)
        except (TypeError, ValueError, OverflowError, CustomUser.DoesNotExist):
            return None

    def get(self, request, uidb64, token):
        user = self._get_user(uidb64)
        if user is None or not default_token_generator.check_token(user, token):
            messages.error(request, 'This password reset link is invalid or has already been used.')
            return redirect('accounts:forgot_password')
        return render(request, self.template_name, {
            'form': SetNewPasswordForm(),
            'uidb64': uidb64,
            'token': token,
        })

    def post(self, request, uidb64, token):
        user = self._get_user(uidb64)
        if user is None or not default_token_generator.check_token(user, token):
            messages.error(request, 'This password reset link is invalid or has already been used.')
            return redirect('accounts:forgot_password')
        form = SetNewPasswordForm(request.POST)
        if form.is_valid():
            user.set_password(form.cleaned_data['new_password1'])
            user.save()
            messages.success(request, 'Password reset successfully. Please log in with your new password.')
            return redirect('accounts:login')
        return render(request, self.template_name, {
            'form': form,
            'uidb64': uidb64,
            'token': token,
        })
