from rest_framework import serializers
from django.contrib.auth.models import User, Group
from .models import (
    TblClient,
    TblDepartment,
    TblVendor,
    TblJobDescription,
    TblImpDepartment,
    TblClientDocument,
    TblVendorDocument,
    UserClient,
    AssignJd,
    UserRecruiterMapping,
    ImplementerPortalConfig,
    TblCandidateProfile,
    TblCandidateResume,
    L0InterviewList,
    L0InterviewSessions,
    TblMatchedProfiles,
    TblMatchedProfilesCandidate,
    career
)
from admin_users.models import ImplementerDetails
from django.utils import timezone
import math
from auditlog.models import LogEntry

class ImplementerDetailsLiteSerializer(serializers.ModelSerializer):
    class Meta:
        model = ImplementerDetails
        fields = (
            "id",
            "name",
            "display_name",
            "reference_id",
            "status",
        )

class ClientDocumentSerializer(serializers.ModelSerializer):
    document = serializers.FileField(use_url=True)

    class Meta:
        model = TblClientDocument
        fields = ["id", "document", "uploaded_date"]

class TblImpDepartmentSerializer(serializers.ModelSerializer):
    implementer = ImplementerDetailsLiteSerializer(read_only=True)

    class Meta:
        model = TblImpDepartment
        fields = "__all__"
        read_only_fields = ("imp_department_id", "created_date", "updated_date", "implementer")

    def validate_imp_department_name(self, value):
        qs = TblImpDepartment.objects.filter(imp_department_name__iexact=value)

        if self.instance:
            qs = qs.exclude(imp_department_id=self.instance.imp_department_id)

        if qs.exists():
            raise serializers.ValidationError(
                "Department Name already exists."
            )
        return value

    def validate_imp_dep_contact_email(self, value):
        qs = TblImpDepartment.objects.filter(imp_dep_contact_email__iexact=value)

        if self.instance:
            qs = qs.exclude(imp_department_id=self.instance.imp_department_id)

        if qs.exists():
            raise serializers.ValidationError(
                "Department email already exists."
            )
        return value

    def validate(self, attrs):
        """
        Validate country code + contact number combination
        """
        country_code = attrs.get(
            "imp_dep_country_code",
            self.instance.imp_dep_country_code if self.instance else None
        )
        contact_number = attrs.get(
            "imp_dep_contact_number",
            self.instance.imp_dep_contact_number if self.instance else None
        )

        if country_code and contact_number:
            qs = TblImpDepartment.objects.filter(
                imp_dep_country_code=country_code,
                imp_dep_contact_number=contact_number
            )

            if self.instance:
                qs = qs.exclude(imp_department_id=self.instance.imp_department_id)

            if qs.exists():
                raise serializers.ValidationError({
                    "imp_dep_contact_number":
                        "Department contact number already exists with this country code."
                })

        return attrs
class ClientSerializer(serializers.ModelSerializer):
    client_type = serializers.CharField(
        required=False,
        allow_blank=True,
        default="End"
    )

    documents = ClientDocumentSerializer(many=True, read_only=True)

    client_logo = serializers.ImageField(
        use_url=True,
        required=False,
        allow_null=True
    )

    imp_department = TblImpDepartmentSerializer(read_only=True)

    imp_department_id = serializers.PrimaryKeyRelatedField(
        queryset=TblImpDepartment.objects.all(),
        source="imp_department",
        required=False,
        allow_null=True,
        write_only=True
    )

    class Meta:
        model = TblClient
        fields = "__all__"
        read_only_fields = ("client_id", "created_date", "updated_date")

    def validate_client_name(self, value):
        qs = TblClient.objects.filter(client_name__iexact=value)

        if self.instance:
            qs = qs.exclude(client_id=self.instance.client_id)

        if qs.exists():
            raise serializers.ValidationError(
                "Client name already exists."
            )
        return value

    def validate_client_contact_email(self, value):
        qs = TblClient.objects.filter(client_contact_email__iexact=value)

        if self.instance:
            qs = qs.exclude(client_id=self.instance.client_id)

        if qs.exists():
            raise serializers.ValidationError(
                "Client contact email already exists."
            )
        return value

    def validate(self, attrs):
        """
        Validate country code + contact number combination
        """
        country_code = attrs.get(
            "client_country_code",
            self.instance.client_country_code if self.instance else None
        )
        contact_number = attrs.get(
            "client_contact_number",
            self.instance.client_contact_number if self.instance else None
        )

        if country_code and contact_number:
            qs = TblClient.objects.filter(
                client_country_code=country_code,
                client_contact_number=contact_number
            )

            if self.instance:
                qs = qs.exclude(client_id=self.instance.client_id)

            if qs.exists():
                raise serializers.ValidationError({
                    "client_contact_number":
                        "Client contact number already exists with this country code."
                })

        return attrs

class TblDepartmentSerializer(serializers.ModelSerializer):
    client = ClientSerializer(read_only=True)

    client_id = serializers.PrimaryKeyRelatedField(
        queryset=TblClient.objects.all(),
        source="client",
        write_only=True
    )
    class Meta:
        model = TblDepartment
        fields = "__all__"
        read_only_fields = ("department_id", "created_date", "updated_date")
    
    def validate_department_name(self, value):
        qs = TblDepartment.objects.filter(department_name__iexact=value)

        if self.instance:
            qs = qs.exclude(department_id=self.instance.department_id)

        if qs.exists():
            raise serializers.ValidationError(
                "Department Name already exists."
            )
        return value

    def validate_dep_contact_email(self, value):
        qs = TblDepartment.objects.filter(dep_contact_email__iexact=value)

        if self.instance:
            qs = qs.exclude(department_id=self.instance.department_id)

        if qs.exists():
            raise serializers.ValidationError(
                "Department email already exists."
            )
        return value

    def validate(self, attrs):
        """
        Validate country code + contact number combination
        """
        country_code = attrs.get(
            "dep_country_code",
            self.instance.dep_country_code if self.instance else None
        )
        contact_number = attrs.get(
            "dep_contact_number",
            self.instance.dep_contact_number if self.instance else None
        )

        if country_code and contact_number:
            qs = TblDepartment.objects.filter(
                dep_country_code=country_code,
                dep_contact_number=contact_number
            )

            if self.instance:
                qs = qs.exclude(department_id=self.instance.department_id)

            if qs.exists():
                raise serializers.ValidationError({
                    "dep_contact_number":
                        "Department contact number already exists with this country code."
                })

        return attrs

class VendorDocumentSerializer(serializers.ModelSerializer):
    document = serializers.FileField(use_url=True)

    class Meta:
        model = TblVendorDocument
        fields = ["id", "document", "uploaded_date"]

class VendorSerializer(serializers.ModelSerializer):
    vendor_logo = serializers.ImageField(
        use_url=True,
        required=False,
        allow_null=True
    )

    class Meta:
        model = TblVendor
        fields = "__all__"
        read_only_fields = ("vendor_id", "created_date", "updated_date")

    def validate_vendor_name(self, value):
        qs = TblVendor.objects.filter(vendor_name__iexact=value)

        if self.instance:
            qs = qs.exclude(vendor_id=self.instance.vendor_id)

        if qs.exists():
            raise serializers.ValidationError(
                "Vendor Name already exists."
            )
        return value

    def validate_vendor_contact_email(self, value):
        qs = TblVendor.objects.filter(vendor_contact_email__iexact=value)

        if self.instance:
            qs = qs.exclude(vendor_id=self.instance.vendor_id)

        if qs.exists():
            raise serializers.ValidationError(
                "Vendor email already exists."
            )
        return value

    def validate(self, attrs):
        """
        Validate country code + contact number combination
        """
        country_code = attrs.get(
            "vendor_country_code",
            self.instance.vendor_country_code if self.instance else None
        )
        contact_number = attrs.get(
            "vendor_contact_number",
            self.instance.vendor_contact_number if self.instance else None
        )

        if country_code and contact_number:
            qs = TblVendor.objects.filter(
                vendor_country_code=country_code,
                vendor_contact_number=contact_number
            )

            if self.instance:
                qs = qs.exclude(vendor_id=self.instance.vendor_id)

            if qs.exists():
                raise serializers.ValidationError({
                    "vendor_contact_number":
                        "Vendor contact number already exists with this country code."
                })

        return attrs

class TblJobDescriptionSerializer(serializers.ModelSerializer):
    assigned_recruiters = serializers.SerializerMethodField()
    linkedin_posts_count = serializers.IntegerField(read_only=True)
    class Meta:
        model = TblJobDescription
        fields = ('__all__' )
        read_only_fields = ("jd_id", "created_date", "updated_date", "jd_display_id")
        
    def get_assigned_recruiters(self, obj):
        return list(
            AssignJd.objects.filter(jd=obj)
            .values_list("user__username", flat=True)
        )

class UserClientSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserClient
        fields = ("client",)

class AssignJdSerializer(serializers.ModelSerializer):
    departments = serializers.PrimaryKeyRelatedField(
        queryset=TblDepartment.objects.all(),
        many=True,
        required=False
    )

    class Meta:
        model = AssignJd
        fields = (
            "id",
            "user",
            "client",
            "jd",
            "departments",
            "status",
        )
        read_only_fields = ("client",)

class UserRecruiterMappingSerializer(serializers.ModelSerializer):
    recruiter_name = serializers.CharField(
        source="recruiter.username",
        read_only=True
    )

    class Meta:
        model = UserRecruiterMapping
        fields = ("recruiter", "recruiter_name")

class ImplementerPortalConfigSerializer(serializers.ModelSerializer):
    class Meta:
        model = ImplementerPortalConfig
        fields = "__all__"
        read_only_fields = (
            "access_token",
            "refresh_token",
            "expires_at",
            "portal_user_urn",
            "is_connected",
            "created_at",
            "updated_at",
        )
    def validate(self, data):
        portal = data.get("portal")

        if portal == "linkedin":
            if not data.get("client_id") or not data.get("client_secret") or not data.get("redirect_uri"):
                raise serializers.ValidationError("LinkedIn credentials required")

        if portal == "naukri":
            if not data.get("portal_username") or not data.get("portal_password"):
                raise serializers.ValidationError("Naukri credentials required")
        
        if portal in ["foundit", "monster"]:
            if not data.get("portal_username") or not data.get("portal_password"):
                raise serializers.ValidationError("Foundit (Monster) requires both username and password.")
            
        if data.get("has_token") is True:
            if not data.get("token"):
                raise serializers.ValidationError({
                    "token": "Token is required"
                })
            if not data.get("urn"):
                raise serializers.ValidationError({
                    "urn": "URN is required"
                })

        return data

class TblCandidateProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = TblCandidateProfile
        fields = ('__all__' )
        read_only_fields = ("id", "created_dt", "updated_dt")

class TblCandidateResumeSerializer(serializers.ModelSerializer):
    class Meta:
        model = TblCandidateResume
        fields = ('__all__' )
        read_only_fields = ("resume_id", "created_dt", "updated_dt")

class careerSerializer(serializers.ModelSerializer):
    logo = serializers.ImageField(use_url=True, required=False)
    class Meta:
        model = career
        fields = "__all__"
        extra_kwargs = {
            "db_password": {"write_only": True}
        }

class ResumeBasicSerializer(serializers.ModelSerializer):
    candidate_name = serializers.SerializerMethodField()
    candidate_email = serializers.SerializerMethodField()
    candidate_mobile_number = serializers.SerializerMethodField()
    candidate_photo = serializers.SerializerMethodField()
    l0_present = serializers.SerializerMethodField()
    l0_completed_time = serializers.SerializerMethodField()
    l0_result = serializers.SerializerMethodField()

    class Meta:
        model = TblCandidateResume
        fields = ["resume_id", "location", "totalexp", "candidate_name", "candidate_email", "candidate_mobile_number", "title", "candidate_photo", "primary_skills", "tools_and_frameworks", "technical_skills", "l0_present", "l0_completed_time", "l0_result" ]

    def get_candidate_name(self, obj):
        return f"{obj.candidate_id.first_name} {obj.candidate_id.last_name}"
    
    def get_candidate_email(self, obj):
        return f"{obj.candidate_id.email}"
    
    def get_candidate_mobile_number(self, obj):
        return f"{obj.candidate_id.mobile_number}"
    
    def get_candidate_photo(self, obj):
        photo = obj.candidate_id.candidate_photo

        if not photo:
            return None

        request = self.context.get("request")
        if request:
            return request.build_absolute_uri(photo.url)

        return photo.url
    
    def get_l0_present(self, obj):
        return self.context.get("l0_present", False)
    
    def get_l0_completed_time(self, obj):
        return self.context.get("l0_completed_time", None)
    
    def get_l0_result(self, obj):
        return self.context.get("l0_result", None)
    
class L0InterviewListSerializer(serializers.ModelSerializer):
    class Meta:
        model = L0InterviewList
        fields = "__all__"

class L0InterviewSessionsSerializer(serializers.ModelSerializer):
    class Meta:
        model = L0InterviewSessions
        fields = "__all__"

class TblMatchedProfilesSerializer(serializers.ModelSerializer):
    status_duration = serializers.SerializerMethodField()

    class Meta:
        model = TblMatchedProfiles
        fields = "__all__"

    def get_status_duration(self, obj):
        if not obj.status_updated_at:
            return None

        now = timezone.now()
        diff = now - obj.status_updated_at

        days = max(1, math.ceil(diff.total_seconds() / 86400))

        return f"{days}d"
    
class TblMatchedProfilesCandidateSerializer(serializers.ModelSerializer):
    jd_display_id = serializers.SerializerMethodField()
    job_title = serializers.SerializerMethodField()

    class Meta:
        model = TblMatchedProfilesCandidate
        fields = "__all__"   # This now includes the two above fields

    def get_jd_display_id(self, obj):
        job = TblJobDescription.objects.filter(jd_id=obj.jd_id).first()
        return job.jd_display_id if job else None

    def get_job_title(self, obj):
        job = TblJobDescription.objects.filter(jd_id=obj.jd_id).first()
        return job.job_title if job else None
    
class JobSerializer(serializers.ModelSerializer):
    class Meta:
        model = TblJobDescription
        fields = "__all__"

class AuditLogSerializer(serializers.ModelSerializer):

    actor = serializers.SerializerMethodField()
    model = serializers.SerializerMethodField()
    changes = serializers.SerializerMethodField()
    action = serializers.SerializerMethodField()

    class Meta:
        model = LogEntry
        fields = [
            "id",
            "actor",
            "action",
            "model",
            "object_id",
            "object_repr",
            "changes",
            "timestamp"
        ]

    def get_actor(self, obj):
        return obj.actor.username if obj.actor else "system"

    def get_action(self, obj):
        action_map = {
            0: "CREATE",
            1: "UPDATE",
            2: "DELETE"
        }
        return action_map.get(obj.action, "UNKNOWN")

    def get_model(self, obj):
        return obj.content_type.model

    def get_changes(self, obj):
        if not obj.changes:
            return None

        formatted = []

        for field, values in obj.changes.items():
            old, new = values
            formatted.append({
                "field": field,
                "old": old,
                "new": new
            })

        return formatted
