import logging

from rest_framework import status
from rest_framework.permissions import BasePermission, IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from django_workflows.users.services.auth_flow import (
    admin_register_user_and_send_setup_email,
    change_password,
    get_user_details,
    list_users,
    register_user_and_send_verification_email,
    send_forgot_password_code,
    update_user,
    verify_reset_code,
)

logger = logging.getLogger(__name__)


def _user_has_group(user, group_name):
    if not user or not getattr(user, "is_authenticated", False):
        return False

    group_manager = getattr(user, "groups", None)
    if group_manager is None:
        return False

    if hasattr(group_manager, "filter"):
        filtered_groups = group_manager.filter(name=group_name)
        if hasattr(filtered_groups, "exists"):
            return filtered_groups.exists()

    if hasattr(group_manager, "all"):
        return any(getattr(group, "name", None) == group_name for group in group_manager.all())

    return False


class HasTimeEntryAdminGroup(BasePermission):
    message = "Time Entry Admin group membership is required."

    def has_permission(self, request, view):
        return _user_has_group(request.user, "Time Entry Admin")


class AnonymousWorkflowView(APIView):
    authentication_classes = []
    permission_classes = []


# Route: POST /forgot-password/
# Body params: email, optional company honeypot field
class ForgotPasswordView(AnonymousWorkflowView):
    def post(self, request):
        data = request.data

        if data.get("company") is not None and str(data.get("company")).strip():
            logger.warning(
                "Honeypot triggered for password reset: company=%s",
                data.get("company"),
            )
            return Response(
                {"detail": "Password reset blocked."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        email = data.get("email")
        if not email:
            logger.error("ForgotPasswordView: Email is required.")
            return Response(
                {"detail": "Email is required."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        result = send_forgot_password_code(email)
        return Response({"detail": result.message}, status=status.HTTP_200_OK)


# Route: POST /register/
# Body params: firstName, lastName, email, password, optional username, optional company honeypot field, optional groups as [{name, enabled}]
# Notes: anonymous self-registration flow; user chooses password and receives a verification code by email
class UserCreateView(AnonymousWorkflowView):
    def post(self, request):
        data = request.data

        if data.get("company") is not None and str(data.get("company")).strip():
            logger.warning(
                "Honeypot triggered for registration: company=%s",
                data.get("company"),
            )
            return Response(
                {"detail": "Bot detected. Registration blocked."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        required_fields = ["firstName", "lastName", "password", "email"]
        missing_fields = [field for field in required_fields if field not in data]
        if missing_fields:
            logger.error("Registration missing fields: %s", missing_fields)
            return Response(
                {"detail": f"Missing required field(s): {', '.join(missing_fields)}"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        result = register_user_and_send_verification_email(
            first_name=data.get("firstName"),
            last_name=data.get("lastName"),
            email=data.get("email"),
            password=data.get("password"),
            username=data.get("username"),
            groups=data.get("groups"),
        )

        if not result.success:
            response_status = status.HTTP_409_CONFLICT
            if result.message != "A user with this email already exists.":
                response_status = status.HTTP_400_BAD_REQUEST

            return Response({"detail": result.message}, status=response_status)

        return Response({"detail": result.message}, status=status.HTTP_201_CREATED)


# Route: POST /admin-register/
# Access: authenticated users in the Time Entry Admin group
# Body params: firstName, lastName, email, optional username, optional company honeypot field, optional groups as [{name, enabled}]
# Notes: server generates a strong password, creates an active user, and sends an informational email without verification code logic
class AdminUserCreateView(APIView):
    permission_classes = [IsAuthenticated, HasTimeEntryAdminGroup]

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

        if data.get("company") is not None and str(data.get("company")).strip():
            logger.warning(
                "Honeypot triggered for admin registration: company=%s",
                data.get("company"),
            )
            return Response(
                {"detail": "Bot detected. Registration blocked."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        required_fields = ["firstName", "lastName", "email"]
        missing_fields = [field for field in required_fields if field not in data]
        if missing_fields:
            logger.error("Admin registration missing fields: %s", missing_fields)
            return Response(
                {"detail": f"Missing required field(s): {', '.join(missing_fields)}"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        result = admin_register_user_and_send_setup_email(
            first_name=data.get("firstName"),
            last_name=data.get("lastName"),
            email=data.get("email"),
            username=data.get("username"),
            groups=data.get("groups"),
        )

        if not result.success:
            response_status = status.HTTP_409_CONFLICT
            if result.message != "A user with this email already exists.":
                response_status = status.HTTP_400_BAD_REQUEST

            return Response({"detail": result.message}, status=response_status)

        return Response({"detail": result.message}, status=status.HTTP_201_CREATED)


# Route: POST /verify-code/
# Body params: email, code, optional company honeypot field
class VerifyCodeView(AnonymousWorkflowView):
    def post(self, request):
        data = request.data

        if data.get("company") is not None and str(data.get("company")).strip():
            logger.warning(
                "Honeypot triggered for verification: company=%s",
                data.get("company"),
            )
            return Response(
                {"detail": "Verification blocked."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        email = data.get("email")
        code = data.get("code")
        if not email or not code:
            return Response(
                {"detail": "Email and code are required."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        result = verify_reset_code(email=email, code=code)
        return Response(result.payload, status=result.status_code)


# Route: POST /change-password/
# Body params: email, password, passwordVerify, optional company honeypot field
class ChangePasswordView(AnonymousWorkflowView):
    def post(self, request):
        data = request.data

        if data.get("company") is not None and str(data.get("company")).strip():
            logger.warning(
                "Honeypot triggered for change password: company=%s",
                data.get("company"),
            )
            return Response(
                {"detail": "Bot detected. Change password blocked."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        result = change_password(
            email=data.get("email"),
            password=data.get("password"),
            password_verify=data.get("passwordVerify"),
        )

        if not result.success:
            return Response(
                {"detail": result.message},
                status=status.HTTP_400_BAD_REQUEST,
            )

        return Response({"detail": result.message}, status=status.HTTP_200_OK)


# Route: GET /users/
# Query params: optional exclude_group as comma-separated group names; users in the Superuser group are always excluded
class UserListView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        users = list_users(exclude_groups=request.query_params.get("exclude_group"))
        logger.info("UserListView: Fetched %s users", len(users))
        return Response(users, status=status.HTTP_200_OK)


# Route: GET /user/
# Route: PATCH /user/
# PATCH body params: username, email, firstName, lastName, password, isActive, optional groups as [{name, enabled}]
class UserDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        data = get_user_details(request.user)
        logger.info("UserDetailView: Fetched details for user %s", request.user.email)
        return Response(data, status=status.HTTP_200_OK)

    def patch(self, request):
        result = update_user(request.user, request.data)

        if result.success:
            return Response(
                {"detail": result.message},
                status=status.HTTP_200_OK,
            )

        logger.error("UserDetailView: %s for user %s", result.message, request.user.email)
        return Response({"detail": result.message}, status=status.HTTP_400_BAD_REQUEST)
