from rest_framework import serializers
from .models import (
    CarBooking, Reimbursement, ReimbursementReceipt, PaymentRequest, DocumentRequest,
    LetterPrefix, LetterNumber, Announcement, SOPCategory, SOP, SOPVersion, InternalGuide,
    HelpdeskTicket
)


class CarBookingSerializer(serializers.ModelSerializer):
    """Serializer for CarBooking model."""
    requester_name = serializers.SerializerMethodField()
    approved_by_name = serializers.SerializerMethodField()
    vehicle_label = serializers.SerializerMethodField()
    vehicle_tag = serializers.SerializerMethodField()

    class Meta:
        model = CarBooking
        fields = [
            "id", "requester", "requester_name",
            "vehicle", "vehicle_name", "vehicle_label", "vehicle_tag", "purpose",
            "start_datetime", "end_datetime", "destination", "number_of_passengers",
            "status", "approved_by", "approved_by_name", "notes", "created_at"
        ]
        read_only_fields = ["id", "requester", "created_at"]

    def get_requester_name(self, obj):
        return obj.requester.get_full_name() or obj.requester.username

    def get_approved_by_name(self, obj):
        if obj.approved_by:
            return obj.approved_by.get_full_name() or obj.approved_by.username
        return None

    def get_vehicle_label(self, obj):
        if obj.vehicle_id:
            return obj.vehicle.name
        return obj.vehicle_name or None

    def get_vehicle_tag(self, obj):
        return obj.vehicle.asset_tag if obj.vehicle_id else None

    # Statuses that no longer hold the vehicle — don't block new bookings.
    INACTIVE_STATUSES = ("cancelled", "rejected")

    def validate(self, attrs):
        instance = self.instance
        vehicle = attrs.get("vehicle", getattr(instance, "vehicle", None))
        start = attrs.get("start_datetime", getattr(instance, "start_datetime", None))
        end = attrs.get("end_datetime", getattr(instance, "end_datetime", None))
        status = attrs.get("status", getattr(instance, "status", "pending"))

        if start and end and end <= start:
            raise serializers.ValidationError(
                {"end_datetime": "End time must be after start time."}
            )

        # Conflict check — only when this booking actively holds a vehicle.
        if vehicle and start and end and status not in self.INACTIVE_STATUSES:
            clashes = (
                CarBooking.objects.filter(
                    vehicle=vehicle,
                    start_datetime__lt=end,
                    end_datetime__gt=start,
                )
                .exclude(status__in=self.INACTIVE_STATUSES)
            )
            if instance is not None:
                clashes = clashes.exclude(pk=instance.pk)
            conflict = clashes.select_related("requester").first()
            if conflict is not None:
                from django.utils import timezone as _tz
                cs = _tz.localtime(conflict.start_datetime)
                ce = _tz.localtime(conflict.end_datetime)
                who = conflict.requester.get_full_name() or conflict.requester.username
                raise serializers.ValidationError(
                    f"{vehicle.name} is already booked "
                    f"{cs:%d %b %Y %H:%M}–{ce:%H:%M} by {who} ({conflict.get_status_display()}). "
                    f"Choose another vehicle or time slot."
                )
        return attrs


class ReimbursementReceiptSerializer(serializers.ModelSerializer):
    """Serializer for an uploaded reimbursement receipt file."""
    file_url = serializers.SerializerMethodField()
    file_name = serializers.SerializerMethodField()
    uploaded_by_name = serializers.SerializerMethodField()

    class Meta:
        model = ReimbursementReceipt
        fields = [
            "id", "reimbursement", "file", "file_url", "file_name",
            "uploaded_by", "uploaded_by_name", "created_at",
        ]
        read_only_fields = ["id", "uploaded_by", "created_at"]

    def get_file_url(self, obj):
        if not obj.file:
            return None
        request = self.context.get("request")
        url = obj.file.url
        return request.build_absolute_uri(url) if request else url

    def get_file_name(self, obj):
        if not obj.file:
            return None
        return obj.file.name.rsplit("/", 1)[-1]

    def get_uploaded_by_name(self, obj):
        if obj.uploaded_by:
            return obj.uploaded_by.get_full_name() or obj.uploaded_by.username
        return None


class ReimbursementSerializer(serializers.ModelSerializer):
    """Serializer for Reimbursement model."""
    requester_name = serializers.SerializerMethodField()
    approved_by_name = serializers.SerializerMethodField()
    receipt_files = ReimbursementReceiptSerializer(many=True, read_only=True)

    class Meta:
        model = Reimbursement
        fields = [
            "id", "requester", "requester_name", "title", "description", "amount",
            "receipts", "receipt_files", "status", "approved_by", "approved_by_name",
            "paid_at", "notes", "created_at"
        ]
        read_only_fields = ["id", "requester", "created_at"]

    def get_requester_name(self, obj):
        return obj.requester.get_full_name() or obj.requester.username

    def get_approved_by_name(self, obj):
        if obj.approved_by:
            return obj.approved_by.get_full_name() or obj.approved_by.username
        return None


class PaymentRequestSerializer(serializers.ModelSerializer):
    """Serializer for PaymentRequest model."""
    requester_name = serializers.SerializerMethodField()
    approved_by_name = serializers.SerializerMethodField()
    source_invoice_number = serializers.SerializerMethodField()

    class Meta:
        model = PaymentRequest
        fields = [
            "id", "requester", "requester_name", "title", "description", "amount",
            "payee", "bank_account", "status", "source_invoice", "source_invoice_number",
            "approved_by", "approved_by_name", "paid_at", "notes", "created_at"
        ]
        read_only_fields = ["id", "requester", "created_at"]

    def get_requester_name(self, obj):
        return obj.requester.get_full_name() or obj.requester.username

    def get_approved_by_name(self, obj):
        if obj.approved_by:
            return obj.approved_by.get_full_name() or obj.approved_by.username
        return None

    def get_source_invoice_number(self, obj):
        return obj.source_invoice.invoice_number if obj.source_invoice_id else None


class DocumentRequestSerializer(serializers.ModelSerializer):
    """Serializer for DocumentRequest model."""
    requester_name = serializers.SerializerMethodField()
    letter_number = serializers.SerializerMethodField()
    letter_id = serializers.SerializerMethodField()

    class Meta:
        model = DocumentRequest
        fields = ["id", "requester", "requester_name", "document_type", "purpose", "status",
                  "notes", "letter_number", "letter_id", "created_at"]
        read_only_fields = ["id", "requester", "created_at"]

    def get_requester_name(self, obj):
        return obj.requester.get_full_name() or obj.requester.username

    def _latest_letter(self, obj):
        # related_name="letters"; most recent issued letter for this request.
        # Pick in Python from the ViewSet's prefetch — order_by().first() here
        # would bypass the prefetch cache and re-query per row.
        return max(obj.letters.all(), key=lambda l: l.created_at, default=None)

    def get_letter_number(self, obj):
        letter = self._latest_letter(obj)
        return letter.full_number if letter else None

    def get_letter_id(self, obj):
        letter = self._latest_letter(obj)
        return str(letter.id) if letter else None


class LetterPrefixSerializer(serializers.ModelSerializer):
    """Serializer for LetterPrefix (department/unit letter types)."""
    letter_count = serializers.SerializerMethodField()

    class Meta:
        model = LetterPrefix
        fields = ["id", "code", "label", "description", "letter_count", "created_at", "updated_at"]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_letter_count(self, obj):
        cnt = getattr(obj, "letter_count_anno", None)
        return cnt if cnt is not None else obj.letters.count()


class LetterNumberSerializer(serializers.ModelSerializer):
    """Serializer for LetterNumber model."""
    document_request_subject = serializers.SerializerMethodField()
    prefix_code = serializers.CharField(source="prefix.code", read_only=True)
    prefix_label = serializers.CharField(source="prefix.label", read_only=True)

    class Meta:
        model = LetterNumber
        fields = [
            "id", "prefix", "prefix_code", "prefix_label", "year", "month", "sequence",
            "full_number", "subject", "recipient", "sender", "date", "file", "notes",
            "document_request", "document_request_subject", "created_at"
        ]
        read_only_fields = ["id", "sequence", "full_number", "created_at"]

    def get_document_request_subject(self, obj):
        if obj.document_request_id:
            return obj.document_request.document_type
        return None


class AnnouncementSerializer(serializers.ModelSerializer):
    """Serializer for Announcement model."""
    author_name = serializers.SerializerMethodField()

    class Meta:
        model = Announcement
        fields = [
            "id", "title", "content", "priority", "author", "author_name",
            "is_pinned", "valid_from", "valid_until", "attachments", "created_at"
        ]
        read_only_fields = ["id", "created_at"]

    def get_author_name(self, obj):
        return obj.author.get_full_name() or obj.author.username


class SOPCategorySerializer(serializers.ModelSerializer):
    """Serializer for SOPCategory (managed SOP category list)."""
    sop_count = serializers.SerializerMethodField()

    class Meta:
        model = SOPCategory
        fields = ["id", "name", "description", "sop_count", "created_at", "updated_at"]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_sop_count(self, obj):
        cnt = getattr(obj, "sop_count_anno", None)
        if cnt is not None:
            return cnt
        from .models import SOP
        return SOP.objects.filter(category=obj.name).count()


class SOPVersionSerializer(serializers.ModelSerializer):
    """Serializer for an SOP version snapshot."""
    changed_by_name = serializers.SerializerMethodField()

    class Meta:
        model = SOPVersion
        fields = [
            "id", "version", "content", "effective_date", "change_note",
            "changed_by", "changed_by_name", "created_at"
        ]
        read_only_fields = fields

    def get_changed_by_name(self, obj):
        if obj.changed_by:
            return obj.changed_by.get_full_name() or obj.changed_by.username
        return None


class SOPSerializer(serializers.ModelSerializer):
    """Serializer for SOP model."""
    author_name = serializers.SerializerMethodField()
    versions = SOPVersionSerializer(many=True, read_only=True)
    change_note = serializers.CharField(write_only=True, required=False, allow_blank=True)

    class Meta:
        model = SOP
        fields = [
            "id", "code", "title", "category", "content", "version", "status", "tags",
            "effective_date", "author", "author_name", "attachments", "versions",
            "change_note", "created_at", "updated_at"
        ]
        read_only_fields = ["id", "author", "created_at", "updated_at"]

    def get_author_name(self, obj):
        if obj.author:
            return obj.author.get_full_name() or obj.author.username
        return None


class HelpdeskTicketSerializer(serializers.ModelSerializer):
    """Serializer for HelpdeskTicket model."""
    requester_name = serializers.SerializerMethodField()
    assigned_to_name = serializers.SerializerMethodField()
    response_count = serializers.SerializerMethodField()

    class Meta:
        model = HelpdeskTicket
        fields = [
            "id", "ticket_number", "requester", "requester_name", "subject",
            "category", "department", "description", "priority", "status",
            "resolution", "assigned_to", "assigned_to_name", "response_count",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "ticket_number", "requester", "created_at", "updated_at"]

    def get_requester_name(self, obj):
        return obj.requester.get_full_name() or obj.requester.username

    def get_assigned_to_name(self, obj):
        if obj.assigned_to:
            return obj.assigned_to.get_full_name() or obj.assigned_to.username
        return None

    # No threaded responses yet — always 0 until a response model is added.
    def get_response_count(self, obj):
        return 0


class InternalGuideSerializer(serializers.ModelSerializer):
    """Serializer for InternalGuide model."""
    author_name = serializers.SerializerMethodField()

    class Meta:
        model = InternalGuide
        fields = [
            "id", "title", "category", "content", "author", "author_name",
            "tags", "attachments", "created_at", "updated_at"
        ]
        read_only_fields = ["id", "author", "created_at", "updated_at"]

    def get_author_name(self, obj):
        if obj.author:
            return obj.author.get_full_name() or obj.author.username
        return None