"""
inventory/serializers.py
─────────────────────────
DRF serializers for the inventory app.
Read serializers are lean. Write serializers validate business rules.
"""

from decimal import Decimal

from rest_framework import serializers

from catalog_app.models import Author, Book
from inventory.models import (
    AuditLog,
    AuthorPayout,
    AuthorPayoutItem,
    Bookstore,
    Event,
    Expense,
    ExpenseCategory,
    InventoryBalance,
    InventoryTransaction,
    Sale,
    SaleItem,
    StockLocation,
)
from inventory.services.sales_service import calculate_item_margins


# ---------------------------------------------------------------------------
# Stock Locations
# ---------------------------------------------------------------------------

class StockLocationSerializer(serializers.ModelSerializer):
    class Meta:
        model = StockLocation
        fields = ["id", "name", "code", "location_type", "address", "is_active", "created_at"]
        read_only_fields = ["id", "created_at"]


# ---------------------------------------------------------------------------
# Inventory Transaction
# ---------------------------------------------------------------------------

class InventoryTransactionSerializer(serializers.ModelSerializer):
    book_title           = serializers.CharField(source="book.title", read_only=True)
    source_location_name = serializers.CharField(source="source_location.name", read_only=True, default=None)
    dest_location_name   = serializers.CharField(source="destination_location.name", read_only=True, default=None)
    performed_by_name    = serializers.CharField(source="performed_by.username", read_only=True, default=None)
    transaction_type_display = serializers.CharField(source="get_transaction_type_display", read_only=True)

    class Meta:
        model = InventoryTransaction
        fields = [
            "id", "book", "book_title",
            "source_location", "source_location_name",
            "destination_location", "dest_location_name",
            "quantity", "transaction_type", "transaction_type_display",
            "transaction_reference", "is_reversed", "notes",
            "performed_by", "performed_by_name", "created_at",
        ]
        read_only_fields = ["id", "is_reversed", "created_at"]


# ---------------------------------------------------------------------------
# Inventory Balance
# ---------------------------------------------------------------------------

class InventoryBalanceSerializer(serializers.ModelSerializer):
    book_title     = serializers.CharField(source="book.title", read_only=True)
    author_name    = serializers.CharField(source="book.author.name", read_only=True, default=None)
    location_name  = serializers.CharField(source="location.name", read_only=True)
    location_code  = serializers.CharField(source="location.code", read_only=True)
    quantity_available = serializers.IntegerField(read_only=True)
    is_low_stock   = serializers.SerializerMethodField()

    class Meta:
        model = InventoryBalance
        fields = [
            "id", "book", "book_title", "author_name",
            "location", "location_name", "location_code",
            "quantity_on_hand", "quantity_reserved", "quantity_available",
            "is_low_stock",
        ]

    def get_is_low_stock(self, obj: InventoryBalance) -> bool:
        return obj.quantity_on_hand <= obj.book.reorder_level


# ---------------------------------------------------------------------------
# Bookstore
# ---------------------------------------------------------------------------

class BookstoreSerializer(serializers.ModelSerializer):
    class Meta:
        model = Bookstore
        fields = [
            "id", "name", "contact_person", "phone", "email",
            "address", "stock_location", "is_active", "created_at", "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]


# ---------------------------------------------------------------------------
# Event
# ---------------------------------------------------------------------------

class EventSerializer(serializers.ModelSerializer):
    class Meta:
        model = Event
        fields = [
            "id", "name", "venue", "start_date", "end_date",
            "stock_location", "notes", "created_at",
        ]
        read_only_fields = ["id", "created_at"]


# ---------------------------------------------------------------------------
# Sale Item
# ---------------------------------------------------------------------------

class SaleItemReadSerializer(serializers.ModelSerializer):
    book_title   = serializers.CharField(source="book.title", read_only=True)
    author_name  = serializers.CharField(source="book.author.name", read_only=True, default=None)
    location_name = serializers.CharField(source="stock_location.name", read_only=True, default=None)

    class Meta:
        model = SaleItem
        fields = [
            "id", "book", "book_title", "author_name",
            "stock_location", "location_name",
            "quantity", "unit_price", "discount_percent",
            "gross_amount", "discount_amount", "net_amount",
            "my_keep_percent", "author_pay_percent",
            "my_profit_amount", "author_payout_amount",
            "payout_included",
        ]


class SaleItemWriteSerializer(serializers.Serializer):
    book             = serializers.PrimaryKeyRelatedField(queryset=Book.objects.filter(is_listed=True))
    quantity         = serializers.IntegerField(min_value=1)
    unit_price       = serializers.DecimalField(max_digits=10, decimal_places=2)
    discount_percent = serializers.DecimalField(max_digits=5, decimal_places=2, default=Decimal("0"))
    stock_location   = serializers.PrimaryKeyRelatedField(
        queryset=StockLocation.objects.filter(is_active=True),
        required=False, allow_null=True, default=None,
    )


# ---------------------------------------------------------------------------
# Sale
# ---------------------------------------------------------------------------

class SaleReadSerializer(serializers.ModelSerializer):
    items          = SaleItemReadSerializer(many=True, read_only=True)
    recorded_by_name = serializers.CharField(source="recorded_by.username", read_only=True, default=None)
    sale_channel_display = serializers.CharField(source="get_sale_channel_display", read_only=True)

    class Meta:
        model = Sale
        fields = [
            "id", "invoice_number", "sale_channel", "sale_channel_display",
            "customer_name", "customer_phone", "sale_date",
            "bookstore", "event", "linked_order",
            "total_gross", "total_discount", "total_net",
            "total_profit", "total_author_payout",
            "notes", "recorded_by", "recorded_by_name",
            "created_at", "updated_at", "items",
        ]


class SaleCreateSerializer(serializers.Serializer):
    sale_channel     = serializers.ChoiceField(choices=Sale.CHANNELS)
    sale_date        = serializers.DateField()
    customer_name    = serializers.CharField(max_length=255, required=False, allow_blank=True, default="")
    customer_phone   = serializers.CharField(max_length=20, required=False, allow_blank=True, default="")
    bookstore        = serializers.PrimaryKeyRelatedField(
        queryset=Bookstore.objects.filter(is_active=True), required=False, allow_null=True, default=None
    )
    event            = serializers.PrimaryKeyRelatedField(
        queryset=Event.objects.all(), required=False, allow_null=True, default=None
    )
    stock_location   = serializers.PrimaryKeyRelatedField(
        queryset=StockLocation.objects.filter(is_active=True), required=False, allow_null=True, default=None
    )
    notes            = serializers.CharField(required=False, allow_blank=True, default="")
    items            = SaleItemWriteSerializer(many=True)

    def validate_items(self, value):
        if not value:
            raise serializers.ValidationError("At least one item is required.")
        return value


# ---------------------------------------------------------------------------
# Stock Transfer (convenience write serializer)
# ---------------------------------------------------------------------------

class StockTransferSerializer(serializers.Serializer):
    book             = serializers.PrimaryKeyRelatedField(queryset=Book.objects.all())
    source_location  = serializers.PrimaryKeyRelatedField(queryset=StockLocation.objects.filter(is_active=True))
    destination_location = serializers.PrimaryKeyRelatedField(queryset=StockLocation.objects.filter(is_active=True))
    quantity         = serializers.IntegerField(min_value=1)
    reference        = serializers.CharField(max_length=100, required=False, allow_blank=True, default="")
    notes            = serializers.CharField(required=False, allow_blank=True, default="")

    def validate(self, data):
        if data["source_location"] == data["destination_location"]:
            raise serializers.ValidationError("Source and destination must be different.")
        return data


class StockReceiptSerializer(serializers.Serializer):
    book             = serializers.PrimaryKeyRelatedField(queryset=Book.objects.all())
    location         = serializers.PrimaryKeyRelatedField(queryset=StockLocation.objects.filter(is_active=True))
    quantity         = serializers.IntegerField(min_value=1)
    reference        = serializers.CharField(max_length=100, required=False, allow_blank=True, default="")
    notes            = serializers.CharField(required=False, allow_blank=True, default="")


class StockAdjustmentSerializer(serializers.Serializer):
    book             = serializers.PrimaryKeyRelatedField(queryset=Book.objects.all())
    location         = serializers.PrimaryKeyRelatedField(queryset=StockLocation.objects.filter(is_active=True))
    new_quantity     = serializers.IntegerField(min_value=0)
    reference        = serializers.CharField(max_length=100, required=False, allow_blank=True, default="")
    notes            = serializers.CharField(required=False, allow_blank=True, default="")


# ---------------------------------------------------------------------------
# Author Payout
# ---------------------------------------------------------------------------

class AuthorPayoutItemSerializer(serializers.ModelSerializer):
    book_title = serializers.CharField(source="book.title", read_only=True)

    class Meta:
        model = AuthorPayoutItem
        fields = [
            "id", "book", "book_title",
            "gross_earnings", "adjustment_amount", "adjustment_notes", "net_earnings",
        ]


class AuthorPayoutSerializer(serializers.ModelSerializer):
    items         = AuthorPayoutItemSerializer(many=True, read_only=True)
    author_name   = serializers.CharField(source="author.name", read_only=True)
    status_display = serializers.CharField(source="get_status_display", read_only=True)

    class Meta:
        model = AuthorPayout
        fields = [
            "id", "author", "author_name",
            "period_type", "period_start", "period_end",
            "total_earnings", "total_adjustments", "total_paid", "outstanding_balance",
            "status", "status_display",
            "payment_method", "payment_reference", "payment_date",
            "notes", "prepared_by", "approved_by", "approved_at", "paid_at",
            "created_at", "updated_at", "items",
        ]
        read_only_fields = [
            "id", "total_earnings", "total_adjustments", "total_paid",
            "outstanding_balance", "approved_at", "paid_at", "created_at", "updated_at",
        ]


class GeneratePayoutSerializer(serializers.Serializer):
    author       = serializers.PrimaryKeyRelatedField(queryset=Author.objects.all())
    period_type  = serializers.ChoiceField(choices=AuthorPayout.PERIODS)
    period_start = serializers.DateField()
    period_end   = serializers.DateField()
    notes        = serializers.CharField(required=False, allow_blank=True, default="")

    def validate(self, data):
        if data["period_start"] > data["period_end"]:
            raise serializers.ValidationError("period_start must be before period_end.")
        return data


class MarkPayoutPaidSerializer(serializers.Serializer):
    payment_method    = serializers.CharField(max_length=100)
    payment_reference = serializers.CharField(max_length=100)
    payment_date      = serializers.DateField()
    amount_paid       = serializers.DecimalField(max_digits=12, decimal_places=2, required=False, allow_null=True)


# ---------------------------------------------------------------------------
# Expense
# ---------------------------------------------------------------------------

class ExpenseCategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = ExpenseCategory
        fields = ["id", "name", "description"]


class ExpenseSerializer(serializers.ModelSerializer):
    category_name = serializers.CharField(source="category.name", read_only=True)
    recorded_by_name = serializers.CharField(source="recorded_by.username", read_only=True, default=None)

    class Meta:
        model = Expense
        fields = [
            "id", "category", "category_name", "amount", "date", "description",
            "linked_book", "linked_event", "linked_sale",
            "receipt_image", "notes", "recorded_by", "recorded_by_name", "created_at",
        ]
        read_only_fields = ["id", "created_at"]


# ---------------------------------------------------------------------------
# Audit Log
# ---------------------------------------------------------------------------

class AuditLogSerializer(serializers.ModelSerializer):
    username = serializers.CharField(source="user.username", read_only=True, default=None)

    class Meta:
        model = AuditLog
        fields = [
            "id", "user", "username", "action", "model_name",
            "object_id", "object_repr", "old_values", "new_values",
            "ip_address", "timestamp",
        ]


# ---------------------------------------------------------------------------
# Dashboard / Report serializers
# ---------------------------------------------------------------------------

class ProfitLossSerializer(serializers.Serializer):
    period_start           = serializers.DateField()
    period_end             = serializers.DateField()
    gross_revenue          = serializers.DecimalField(max_digits=14, decimal_places=2)
    total_discounts        = serializers.DecimalField(max_digits=14, decimal_places=2)
    net_revenue            = serializers.DecimalField(max_digits=14, decimal_places=2)
    author_payouts         = serializers.DecimalField(max_digits=14, decimal_places=2)
    platform_gross_profit  = serializers.DecimalField(max_digits=14, decimal_places=2)
    total_expenses         = serializers.DecimalField(max_digits=14, decimal_places=2)
    net_profit             = serializers.DecimalField(max_digits=14, decimal_places=2)
    total_units_sold       = serializers.IntegerField()


class MarginPreviewSerializer(serializers.Serializer):
    """Read-only preview of margin calculation for a given book/price/discount."""
    book             = serializers.PrimaryKeyRelatedField(queryset=Book.objects.all())
    quantity         = serializers.IntegerField(min_value=1, default=1)
    unit_price       = serializers.DecimalField(max_digits=10, decimal_places=2)
    discount_percent = serializers.DecimalField(max_digits=5, decimal_places=2, default=Decimal("0"))
