from rest_framework import serializers
from .models import Requisition, RequisitionQuote, Approval, RFQRFP, PurchaseOrder, ProcurementContract, GoodsReceipt, Invoice, Payment


class RequisitionSerializer(serializers.ModelSerializer):
    """Serializer for Requisition model."""
    requested_by_name = serializers.SerializerMethodField()
    vendor_name = serializers.SerializerMethodField()
    budget_item_name = serializers.SerializerMethodField()
    budget_context = serializers.SerializerMethodField()

    class Meta:
        model = Requisition
        fields = [
            "id", "number", "title", "description", "status", "requested_by", "requested_by_name",
            "vendor", "vendor_name", "items", "total_amount",
            "budget_item", "budget_item_name", "budget_context", "notes",
            "created_at", "updated_at",
        ]
        read_only_fields = ["id", "number", "requested_by", "created_at", "updated_at"]

    def get_requested_by_name(self, obj):
        return obj.requested_by.get_full_name() or obj.requested_by.username

    def get_vendor_name(self, obj):
        return obj.vendor.name if obj.vendor_id else None

    def get_budget_item_name(self, obj):
        return obj.budget_item.name if obj.budget_item_id else None

    def get_budget_context(self, obj):
        return obj.budget_context()


class ApprovalSerializer(serializers.ModelSerializer):
    """Serializer for Approval model."""
    approver_name = serializers.SerializerMethodField()
    requisition_title = serializers.SerializerMethodField()
    requisition_number = serializers.SerializerMethodField()
    vendor_name = serializers.SerializerMethodField()

    class Meta:
        model = Approval
        fields = [
            "id", "requisition", "requisition_number", "requisition_title", "vendor_name",
            "level", "required_role", "approver", "approver_name", "status", "comment",
            "resolved_at", "created_at",
        ]
        read_only_fields = ["id", "level", "required_role", "created_at"]

    def get_approver_name(self, obj):
        if not obj.approver_id:
            return None
        return obj.approver.get_full_name() or obj.approver.username

    def get_requisition_title(self, obj):
        return obj.requisition.title if obj.requisition_id else None

    def get_requisition_number(self, obj):
        return obj.requisition.number if obj.requisition_id else None

    def get_vendor_name(self, obj):
        req = obj.requisition
        return req.vendor.name if req and req.vendor_id else None


class RequisitionQuoteSerializer(serializers.ModelSerializer):
    """Serializer for vendor quotes on a requisition."""
    vendor_name = serializers.SerializerMethodField()
    requisition_number = serializers.SerializerMethodField()
    awarded_by_name = serializers.SerializerMethodField()
    is_lowest = serializers.BooleanField(read_only=True)

    class Meta:
        model = RequisitionQuote
        fields = [
            "id", "requisition", "requisition_number", "vendor", "vendor_name",
            "quoted_amount", "delivery_estimate", "is_selected", "is_lowest",
            "award_reason", "awarded_by", "awarded_by_name", "awarded_at",
            "notes", "attachment", "created_at",
        ]
        # Award fields move only through the award action, not direct writes.
        read_only_fields = ["id", "created_at", "is_selected", "award_reason", "awarded_by", "awarded_at"]

    def get_vendor_name(self, obj):
        return obj.vendor.name if obj.vendor_id else None

    def get_requisition_number(self, obj):
        return obj.requisition.number if obj.requisition_id else None

    def get_awarded_by_name(self, obj):
        if not obj.awarded_by_id:
            return None
        return obj.awarded_by.get_full_name() or obj.awarded_by.username


class RFQRFPSerializer(serializers.ModelSerializer):
    """Serializer for RFQRFP model."""
    created_by_name = serializers.SerializerMethodField()
    vendor_name = serializers.SerializerMethodField()

    class Meta:
        model = RFQRFP
        fields = [
            "id", "title", "rfq_rfp_type", "description", "requirements", "deadline",
            "status", "created_by", "created_by_name", "vendor", "vendor_name",
            "attachments", "created_at", "updated_at"
        ]
        read_only_fields = ["id", "created_by", "created_at", "updated_at"]

    def get_created_by_name(self, obj):
        return obj.created_by.get_full_name() or obj.created_by.username

    def get_vendor_name(self, obj):
        if obj.vendor:
            return obj.vendor.name
        return None


class PurchaseOrderSerializer(serializers.ModelSerializer):
    """Serializer for PurchaseOrder model."""
    vendor_name = serializers.SerializerMethodField()
    vendor_address = serializers.SerializerMethodField()
    vendor_contact_person = serializers.SerializerMethodField()
    vendor_email = serializers.SerializerMethodField()
    vendor_phone = serializers.SerializerMethodField()
    vendor_tax_id = serializers.SerializerMethodField()
    requisition_number = serializers.SerializerMethodField()
    requisition_title = serializers.SerializerMethodField()

    class Meta:
        model = PurchaseOrder
        fields = [
            "id", "order_number", "vendor", "vendor_name",
            "vendor_address", "vendor_contact_person", "vendor_email", "vendor_phone", "vendor_tax_id",
            "requisition", "requisition_number", "requisition_title",
            "items", "subtotal", "tax", "total", "status", "expected_delivery",
            "notes", "created_at", "updated_at"
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_vendor_name(self, obj):
        return obj.vendor.name if obj.vendor_id else None

    def get_vendor_address(self, obj):
        return obj.vendor.address if obj.vendor_id else None

    def get_vendor_contact_person(self, obj):
        return obj.vendor.contact_person if obj.vendor_id else None

    def get_vendor_email(self, obj):
        return obj.vendor.email if obj.vendor_id else None

    def get_vendor_phone(self, obj):
        return obj.vendor.phone if obj.vendor_id else None

    def get_vendor_tax_id(self, obj):
        return obj.vendor.tax_id if obj.vendor_id else None

    def get_requisition_number(self, obj):
        return obj.requisition.number if obj.requisition_id else None

    def get_requisition_title(self, obj):
        return obj.requisition.title if obj.requisition_id else None


class ProcurementContractSerializer(serializers.ModelSerializer):
    """Serializer for ProcurementContract model."""
    vendor_name = serializers.SerializerMethodField()

    class Meta:
        model = ProcurementContract
        fields = [
            "id", "title", "contract_number", "vendor", "vendor_name", "value",
            "start_date", "end_date", "status", "document", "terms", "created_at", "updated_at"
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_vendor_name(self, obj):
        return obj.vendor.name if obj.vendor_id else None


class GoodsReceiptSerializer(serializers.ModelSerializer):
    """Serializer for GoodsReceipt model."""
    purchase_order_number = serializers.SerializerMethodField()
    vendor_name = serializers.SerializerMethodField()
    received_by_name = serializers.SerializerMethodField()

    class Meta:
        model = GoodsReceipt
        fields = [
            "id", "purchase_order", "purchase_order_number", "vendor_name", "receipt_number",
            "received_date", "items", "status", "notes", "received_by", "received_by_name", "created_at"
        ]
        read_only_fields = ["id", "created_at"]

    def get_purchase_order_number(self, obj):
        return obj.purchase_order.order_number if obj.purchase_order_id else None

    def get_vendor_name(self, obj):
        po = obj.purchase_order
        return po.vendor.name if po and po.vendor_id else None

    def get_received_by_name(self, obj):
        if obj.received_by:
            return obj.received_by.get_full_name() or obj.received_by.username
        return None


class InvoiceSerializer(serializers.ModelSerializer):
    """Serializer for Invoice model."""
    vendor_name = serializers.SerializerMethodField()
    purchase_order_number = serializers.SerializerMethodField()

    match_detail = serializers.SerializerMethodField()

    class Meta:
        model = Invoice
        fields = [
            "id", "invoice_number", "vendor", "vendor_name",
            "purchase_order", "purchase_order_number",
            "goods_receipt", "amount", "tax", "total", "due_date", "status",
            "match_status", "match_detail",
            "paid_at", "notes", "created_at"
        ]
        read_only_fields = ["id", "created_at", "match_status"]

    def get_vendor_name(self, obj):
        return obj.vendor.name if obj.vendor_id else None

    def get_purchase_order_number(self, obj):
        return obj.purchase_order.order_number if obj.purchase_order_id else None

    def get_match_detail(self, obj):
        return obj.match_detail()


class PaymentSerializer(serializers.ModelSerializer):
    """Serializer for Payment model."""
    invoice_number = serializers.SerializerMethodField()
    vendor_name = serializers.SerializerMethodField()
    invoice_total = serializers.SerializerMethodField()

    class Meta:
        model = Payment
        fields = [
            "id", "invoice", "invoice_number", "vendor_name", "invoice_total",
            "amount", "method", "reference",
            "status", "paid_at", "notes", "created_at"
        ]
        read_only_fields = ["id", "created_at"]

    def get_invoice_number(self, obj):
        return obj.invoice.invoice_number if obj.invoice_id else None

    def get_vendor_name(self, obj):
        inv = obj.invoice
        return inv.vendor.name if inv and inv.vendor_id else None

    def get_invoice_total(self, obj):
        return obj.invoice.total if obj.invoice_id else None

    def validate(self, attrs):
        # 3-way match gate: an invoice must pass PO=GRN=Invoice before it can
        # be paid. Only enforced on create (the initial payment record); status
        # transitions on an existing payment are left alone.
        invoice = attrs.get("invoice") or getattr(self.instance, "invoice", None)
        if self.instance is None and invoice and invoice.match_status != "matched":
            raise serializers.ValidationError(
                {"invoice": f"Invoice failed 3-way match (status: {invoice.match_status}). "
                            "Resolve the PO/GRN/Invoice mismatch before paying."}
            )
        return attrs