from rest_framework.permissions import IsAuthenticated
from django_filters import rest_framework as filters
from django.contrib.auth.models import User, Group, PermissionManager
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_simplejwt.tokens import RefreshToken
from .models import (
    ImplementerDetails,
    TblUserOrganizationAuth,
    UserProfile
)
from .serializers import (
    OrganizationDetailsSerializer,
    AuthUserPermissionsSerializer,
    AuthGroupSerializer
)
from rest_framework import status
from masters.models import UserClient, UserRecruiterMapping
import json
from django.db import transaction
from masters.utils import send_user_created_mail
from rest_framework_simplejwt.views import TokenObtainPairView
from auditlog.models import LogEntry
from django.contrib.contenttypes.models import ContentType
from admin_users.utils import get_client_ip, get_device_type, get_location, get_city_from_coords

class ImplementerDetailsViewSet(viewsets.ModelViewSet):
    permission_classes = (IsAuthenticated,)
    queryset = ImplementerDetails.objects.all().order_by("id")
    serializer_class = OrganizationDetailsSerializer
    filterset_fields = {"id": ["exact"]}
    filter_backends = [filters.DjangoFilterBackend]

class HomeView(APIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request):
        c_user = request.user
        PermissionManager()
        print("user: ", request.user)
        user_permissions = c_user.get_group_permissions()
        return Response(user_permissions)

class LogoutView(APIView):
    permission_classes = (IsAuthenticated,)

    def post(self, request):
        try:
            username = request.data.get("username")
            refresh_token = request.data.get("refresh_token")
            latitude = request.data.get("latitude")
            longitude = request.data.get("longitude")

            user = User.objects.get(username=username)

            ip = get_client_ip(request)
            device = get_device_type(request)

            # If GPS location available use it
            if latitude and longitude:
                location = get_city_from_coords(latitude, longitude)
            else:
                location = get_location(ip)

            LogEntry.objects.create(
                actor=user,
                content_type=ContentType.objects.get_for_model(User),
                object_pk=user.pk,
                object_repr=str(user),
                action=LogEntry.Action.ACCESS,
                changes={
                    "activity": ["Login", "Logout"],
                    "ip_address": ip,
                    "device": device,
                    "location": location,
                    "latitude": latitude,
                    "longitude": longitude
                }
            )

            token = RefreshToken(refresh_token)
            token.blacklist()

            return Response(status=status.HTTP_205_RESET_CONTENT)

        except User.DoesNotExist:
            return Response({"error": "User not found"}, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)

class AuthUserView(viewsets.ModelViewSet):
    # permission_classes = (IsAuthenticated,)
    queryset = User.objects.all()
    serializer_class = AuthUserPermissionsSerializer
    filterset_fields = {
        "username": ["exact"],
        "auth_user_organization__organization": ["exact"],
    }

    def get_queryset(self):
        queryset = User.objects.all()

        role = self.request.query_params.get("role")

        if role == "Recruiter":
            queryset = queryset.filter(groups__name="Recruiter")

        return queryset.distinct()

    def create(self, request):
        organization_id = request.data.get("organization")
        password = request.data.get("password")
        # mobile_number = request.data.get("mobile_number")
        # request.data["is_active"] = True
        user_serializer = AuthUserPermissionsSerializer(data=request.data)
        if user_serializer.is_valid():
            with transaction.atomic():
                user = User.objects.create(
                    username=user_serializer.validated_data["username"],
                    first_name=user_serializer.validated_data.get("first_name", ""),
                    last_name=user_serializer.validated_data.get("last_name", ""),
                    email=user_serializer.validated_data.get("email", ""),
                    is_active=True,
                )
        else:
            # Debug the missing or invalid fields
            print("Validation errors:", user_serializer.errors)
            return Response(user_serializer.errors, status=400)
        user.set_password(request.data["password"])
        user.save()

        full_name = f"{user.first_name} {user.last_name}".strip()

        send_user_created_mail(
            email=user.email,
            username=user.username,
            password=password,
            full_name=full_name,
        )

        profile, created = UserProfile.objects.get_or_create(user=user)

        groups_raw = request.data.get("groups", "[]")
        groups_data = json.loads(groups_raw) if isinstance(groups_raw, str) else groups_raw

        for group_data in groups_data:
            if isinstance(group_data, str):
                group_data = json.loads(group_data)

            group_pk = Group.objects.get(id=group_data["id"])
            user.groups.add(group_pk)

        if organization_id:
            TblUserOrganizationAuth.objects.create(
                user_id=user.id,
                organization_id=organization_id,
                # mobile_number=mobile_number
            )
        clients_raw = request.data.get("client_mappings", "[]")
        clients = json.loads(clients_raw) if isinstance(clients_raw, str) else clients_raw

        for item in clients:
            if isinstance(item, str):
                item = json.loads(item)

            UserClient.objects.create(user=user, client_id=item["client"])

        
        recruiters_raw = request.data.get("recruiters", "[]")
        recruiters = json.loads(recruiters_raw) if isinstance(recruiters_raw, str) else recruiters_raw

        for r in recruiters:
            if isinstance(r, str):
                r = json.loads(r)

            UserRecruiterMapping.objects.create(
                user=user,
                recruiter_id=r["recruiter"]
            )

        profile_image = request.FILES.get("profile_image")
        if profile_image:
            profile.profile_image = profile_image
            profile.save()

        serializer = self.get_serializer(user)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def update(self, request, pk=None, *args, **kwargs):
        user = User.objects.get(id=pk)

        # Update password only logic
        if "password" in request.data:
            user.set_password(request.data["password"])
            user.save()
            return Response({"message": "Password changed successfully."}, status=200)

        organization_id = request.data.get("organization")
        raw_is_active = request.data.get("is_active", user.is_active)

        if isinstance(raw_is_active, str):
            is_active = raw_is_active.lower() == "true"
        else:
            is_active = raw_is_active

        # Update basic fields
        user.username = request.data.get("username", user.username)
        user.first_name = request.data.get("first_name", user.first_name)
        user.last_name = request.data.get("last_name", user.last_name)
        user.email = request.data.get("email", user.email)
        user.is_active = is_active
        user.save()

        groups_raw = request.data.get("groups", [])

        if isinstance(groups_raw, str):
            groups_data = json.loads(groups_raw)
        else:
            groups_data = groups_raw

        user.groups.clear()

        for group_data in groups_data:
            if isinstance(group_data, str):
                group_data = json.loads(group_data)

            group_pk = Group.objects.get(id=group_data["id"])
            user.groups.add(group_pk)

        # Update organization mapping
        if organization_id:
            TblUserOrganizationAuth.objects.filter(user_id=user.id).delete()
            TblUserOrganizationAuth.objects.create(
                user_id=user.id,
                organization_id=organization_id,
            )
        clients_raw = request.data.get("client_mappings", [])

        if isinstance(clients_raw, str):
            clients = json.loads(clients_raw)
        else:
            clients = clients_raw

        UserClient.objects.filter(user=user).delete()

        for item in clients:
            if isinstance(item, str):
                item = json.loads(item)

            UserClient.objects.create(
                user=user,
                client_id=item["client"]
            )

        recruiters_raw = request.data.get("recruiters", [])

        if isinstance(recruiters_raw, str):
            recruiters = json.loads(recruiters_raw)
        else:
            recruiters = recruiters_raw

        UserRecruiterMapping.objects.filter(user=user).delete()

        for r in recruiters:
            if isinstance(r, str):
                r = json.loads(r)

            UserRecruiterMapping.objects.create(
                user=user,
                recruiter_id=r["recruiter"]
            )

        profile_image = request.FILES.get("profile_image")
        if profile_image:
            profile, created = UserProfile.objects.get_or_create(user=user)
            profile.profile_image = profile_image
            profile.save()

        display_column_preference = request.data.get("display_column_preference")
        if display_column_preference is not None:
            profile, created = UserProfile.objects.get_or_create(user=user)
            existing_preferences = profile.display_column_preference or {}
            existing_preferences.update(display_column_preference)
            profile.display_column_preference = existing_preferences
            profile.save()
        
        matched_profiles_column_preference = request.data.get("matched_profiles_column_preference")
        if matched_profiles_column_preference is not None:
            profile, created = UserProfile.objects.get_or_create(user=user)
            existing_preferences = profile.matched_profiles_column_preference or {}
            existing_preferences.update(matched_profiles_column_preference)
            profile.matched_profiles_column_preference = existing_preferences
            profile.save()

        audit_column_preference = request.data.get("audit_column_preference")
        if audit_column_preference is not None:
            profile, created = UserProfile.objects.get_or_create(user=user)
            existing_preferences = profile.audit_column_preference or {}
            existing_preferences.update(audit_column_preference)
            profile.audit_column_preference = existing_preferences
            profile.save()

        serializer = self.get_serializer(user)
        return Response(serializer.data, status=200)
    
    def destroy(self, request, *args, **kwargs):
        user = self.get_object()

        if request.user.id == user.id:
            return Response(
                {"error": "You cannot delete your own account."},
                status=status.HTTP_403_FORBIDDEN
            )

        TblUserOrganizationAuth.objects.filter(user_id=user.id).delete()
        user.delete()

        return Response(status=status.HTTP_204_NO_CONTENT)

class AuthGroupView(viewsets.ModelViewSet):
    permission_classes = (IsAuthenticated,)
    queryset = Group.objects.all().order_by("-id")
    # queryset = User.objects.all()
    serializer_class = AuthGroupSerializer

class CustomTokenObtainPairView(TokenObtainPairView):

    def post(self, request, *args, **kwargs):

        latitude = request.data.get("latitude")
        longitude = request.data.get("longitude")

        response = super().post(request, *args, **kwargs)

        if response.status_code == 200:
            username = request.data.get("username")

            try:
                user = User.objects.get(username=username)

                ip = get_client_ip(request)
                device = get_device_type(request)

                if latitude and longitude:
                    location = get_city_from_coords(latitude, longitude)
                else:
                    location = get_location(ip)

                LogEntry.objects.create(
                    actor=user,
                    content_type=ContentType.objects.get_for_model(User),
                    object_pk=user.pk,
                    object_repr=str(user),
                    action=LogEntry.Action.ACCESS,
                    changes={
                        "activity": ["Logout", "Login"],
                        "ip_address": ip,
                        "device": device,
                        "location": location,
                        "latitude": latitude,
                        "longitude": longitude
                    }
                )

            except User.DoesNotExist:
                pass

        return response
