from django.conf import settings
from django.views.generic import FormView, TemplateView
from django.urls import reverse_lazy
from django.contrib.auth import login, get_user_model
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.utils.encoding import force_bytes, force_str
from apps.core.views.emails import EmailSendError, send_custom_email
from django.template.loader import render_to_string
from django.shortcuts import redirect
from ..forms.forms import RegisterForm, LoginForm, ForgotPasswordForm, PasswordResetConfirmForm
from django.contrib.auth.views import LogoutView
from django.urls import reverse_lazy
from django.contrib.auth.views import PasswordResetConfirmView
from django.contrib.auth import update_session_auth_hash, logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from django.http import JsonResponse
from django.shortcuts import render, redirect
from django.urls import reverse_lazy
from django.views import View
from django.contrib import messages
import json

User = get_user_model()


class RegisterView(FormView):
    form_class = RegisterForm
    success_url = reverse_lazy('users:login')

    def get_template_names(self):
        theme = settings.THEME_NAME
        return [
            f"themes/{theme}/templates/users/login/register.html",
            "themes/default/templates/users/login/register.html"
        ]

    def form_valid(self, form):
        from apps.core.models import EmailSetting
        email_config = EmailSetting.get_solo()
        try:
            # 创建用户

            user = User.objects.create_user(
                username=form.cleaned_data['username'],
                email=form.cleaned_data['email'],
                password=form.cleaned_data['password'],
                is_active=False
                if email_config.email_enabled else True  # 等待邮件激活
            )

            # 尝试发送激活邮件
            if email_config.email_enabled:
                self._send_activation_email(user)
            # 如果发送成功，继续正常流程
            return super().form_valid(form)
        except EmailSendError as e:  # 专门捕获邮件发送异常
            # 1. 记录异常详情到日志，方便管理员排查[2,4](@ref)
            print(
                f"用户注册成功，但激活邮件发送失败 (用户ID: {user.pk if user else 'N/A'}): {str(e)}"
            )

            # 2. 重要：即使邮件发送失败，也认为用户注册行为本身是成功的。
            # 因为用户数据已经创建，可以引导其后续补发激活邮件。
            messages.warning(self.request, "账号注册成功，但激活邮件发送失败。请稍后尝试重新发送激活邮件。")
            # 仍然跳转到成功页面，但提示用户邮件发送问题
            return super().form_valid(form)

        except Exception as e:
            # 如果创建用户或发送邮件失败，返回表单错误
            form.add_error(None, f"注册失败：{str(e)}")
            return self.form_invalid(form)

    def _send_activation_email(self, user):
        """
        封装发送激活邮件的逻辑
        如果发送失败，抛出 EmailSendError
        """
        token = default_token_generator.make_token(user)
        uid = urlsafe_base64_encode(force_bytes(user.pk))
        activate_url = self.request.build_absolute_uri(
            f'/users/activate/{uid}/{token}/')

        theme = settings.THEME_NAME
        template = f"themes/{theme}/templates/emails/welcome.html"
        context = {
            'activate_url': activate_url,
            "username": user.username,
            "code": token
        }
        html_content = render_to_string(template, context)

        # 调用您的 send_custom_email 函数，此处让其正常抛出异常
        send_custom_email(
            subject="激活您的账户",
            message=f'请点击以下链接激活账户：{activate_url}',
            recipient_list=[user.email],
            html_message=html_content,
            # 注意：这里不设置 fail_silently=True，因为我们需要捕获异常进行处理
        )

    def form_invalid(self, form):
        # 这里处理表单验证失败的情况
        # FormView会自动保留用户输入的数据
        return self.render_to_response(self.get_context_data(form=form))


class ActivateView(TemplateView):

    def get_template_names(self):
        theme = settings.THEME_NAME
        return [
            f"themes/{theme}/templates/users/login/activation_result.html",
            "themes/default/templates/users/login/activation_result.html"
        ]

    def get(self, request, *args, **kwargs):
        uidb64 = kwargs['uidb64']
        token = kwargs['token']
        try:
            uid = force_str(urlsafe_base64_decode(uidb64))
            user = User.objects.get(pk=uid)
            if default_token_generator.check_token(user, token):
                user.is_active = True
                user.save()
                return self.render_to_response({'success': True})
        except Exception as e:
            pass
        return self.render_to_response({'success': False})


class LoginView(FormView):
    form_class = LoginForm
    template_name = 'users/login/login.html'

    def get_success_url(self):
        # 优先使用next参数，默认回退到user_index
        return self.request.GET.get('next', reverse_lazy('users:user_index'))

    def get_template_names(self):
        theme = settings.THEME_NAME
        return [
            f"themes/{theme}/templates/users/login/login.html",
            "themes/default/templates/users/login/login.html"
        ]

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['request'] = self.request
        return kwargs

    def form_valid(self, form):
        user = form.get_user()
        login(self.request, user)
        return super().form_valid(form)


class ForgotPasswordView(FormView):
    form_class = ForgotPasswordForm
    success_url = reverse_lazy('user:login')

    def get_template_names(self):
        theme = settings.THEME_NAME
        return [
            f"themes/{theme}/templates/users/login/forgot_password.html",
            "themes/default/templates/users/login/forgot_password.html"
        ]

    def form_valid(self, form):
        email = form.cleaned_data['email']
        users = User.objects.filter(email__iexact=email)
        if users.exists():
            user = users.first()
            token = default_token_generator.make_token(user)
            uid = urlsafe_base64_encode(force_bytes(user.pk))
            reset_url = self.request.build_absolute_uri(
                f'/users/reset-password/{uid}/{token}/')
            theme = settings.THEME_NAME
            template = f"themes/{theme}/templates/emails/base.html",
            context = {
                'message': f'您的用户名是：{user.username}\n请点击重置密码：{reset_url}',
            }
            html_content = render_to_string(template, context)
            send_custom_email(
                subject="密码重置",
                message=f'您的用户名是：{user.username}\n请点击重置密码：{reset_url}',
                recipient_list=[user.email],
                html_message=html_content)

        return super().form_valid(form)


class CustomPasswordResetConfirmView(PasswordResetConfirmView):
    form_class = PasswordResetConfirmForm
    success_url = reverse_lazy('users:login')
    token_generator = default_token_generator

    def get_template_names(self):
        theme = getattr(settings, 'THEME_NAME', 'default')
        return [
            f'themes/{theme}/templates/users/login/password_reset_confirm.html',
            'themes/default/templates/users/login/password_reset_confirm.html'
        ]


class CustomLogoutView(LogoutView):
    """自定义退出登录视图，须使用POST方法"""
    next_page = reverse_lazy('user:login')  # 退出后跳转到登录页（修改为你的路由名）


class ChangePasswordView(LoginRequiredMixin, View):
    """修改密码视图"""
    login_url = '/users/login/'
    template_name = 'users/center/change_password.html'
    success_url = reverse_lazy('users:user_index')

    def get(self, request):
        return render(request, self.template_name)

    def post(self, request):
        user = request.user

        # 获取参数
        data = json.loads(
            request.body
        ) if request.content_type == 'application/json' else request.POST
        old_password = data.get('old_password')
        new_password1 = data.get('new_password1')
        new_password2 = data.get('new_password2')

        # 参数验证
        if not all([old_password, new_password1, new_password2]):
            return self._error_response('所有字段都是必填的')

        # 验证旧密码
        if not user.check_password(old_password):
            return self._error_response('当前密码输入不正确')

        # 验证新密码是否一致
        if new_password1 != new_password2:
            return self._error_response('两次输入的新密码不一致')

        # 验证新密码是否与旧密码相同
        if old_password == new_password1:
            return self._error_response('新密码不能与旧密码相同')

        # 验证密码强度
        try:
            validate_password(new_password1, user)
        except ValidationError as e:
            return self._error_response('; '.join(e.messages))

        # 更新密码
        user.set_password(new_password1)
        user.save()

        # 保持用户登录状态（更新session）
        update_session_auth_hash(request, user)

        # 根据请求类型返回响应
        if request.content_type == 'application/json':
            return JsonResponse({'success': True, 'message': '密码修改成功'})

        messages.success(request, '密码修改成功！')
        return redirect(self.success_url)

    def _error_response(self, message):
        if self.request.content_type == 'application/json':
            return JsonResponse({
                'success': False,
                'message': message
            },
                                status=400)
        messages.error(self.request, message)
        return render(self.request, self.template_name)
