"""John Pye auction tracking models."""

from datetime import datetime
from decimal import Decimal
from enum import Enum

from pydantic import BaseModel, Field, computed_field


class InvoiceStatus(str, Enum):
    """Payment status of an invoice."""

    NEW = "new"
    PAID = "paid"


class DeliveryStatus(str, Enum):
    """Delivery status for paid invoices."""

    PAID = "paid"
    PREPARING = "preparing"
    PACKED = "packed"
    SHIPPED = "shipped"
    DELIVERED = "delivered"


class DeliveryType(str, Enum):
    """How the items will be received."""

    COLLECTION = "collection"
    PARCEL = "parcel_delivery"


class LotItem(BaseModel):
    """Individual lot within an invoice."""

    lot_number: int
    description: str
    hammer_price: Decimal = Field(description="Hammer price in GBP")
    vat: Decimal = Field(default=Decimal("0"))
    subtotal: Decimal = Field(description="hammer_price + vat")
    listing_id: str | None = None


class Invoice(BaseModel):
    """A John Pye invoice."""

    id: str = ""  # UUID in real DB, simple string in mock
    invoice_number: str
    user_id: str = ""
    created_at: datetime = Field(default_factory=datetime.now)
    auction_name: str
    auction_location: str | None = None
    viewing_datetime: str | None = None
    payment_deadline: datetime | None = None
    delivery_type: DeliveryType = DeliveryType.COLLECTION
    delivery_method: str | None = None

    items: list[LotItem] = Field(default_factory=list)

    items_subtotal: Decimal = Decimal("0")
    delivery_cost: Decimal = Decimal("0")
    buyers_premium: Decimal = Decimal("0")
    total_vat: Decimal = Decimal("0")
    grand_total: Decimal = Decimal("0")

    invoice_status: InvoiceStatus = InvoiceStatus.NEW
    delivery_status: DeliveryStatus | None = None
    notes: str | None = None

    @computed_field
    @property
    def item_count(self) -> int:
        """Number of lot items in this invoice."""
        return len(self.items)

    def to_db_row(self) -> dict:
        """Convert to database row format (pence for money)."""
        return {
            "id": self.id,
            "user_id": self.user_id,
            "invoice_number": self.invoice_number,
            "created_at": self.created_at,
            "auction_name": self.auction_name,
            "auction_location": self.auction_location,
            "viewing_datetime": self.viewing_datetime,
            "payment_deadline": self.payment_deadline,
            "delivery_type": self.delivery_type.value,
            "delivery_method": self.delivery_method,
            "items_subtotal_pence": int(self.items_subtotal * 100),
            "delivery_cost_pence": int(self.delivery_cost * 100),
            "buyers_premium_pence": int(self.buyers_premium * 100),
            "total_vat_pence": int(self.total_vat * 100),
            "grand_total_pence": int(self.grand_total * 100),
            "invoice_status": self.invoice_status.value,
            "delivery_status": self.delivery_status.value if self.delivery_status else None,
            "notes": self.notes,
        }

    @classmethod
    def from_db_row(cls, row: dict, items: list[dict] | None = None) -> "Invoice":
        """Create Invoice from database row."""
        return cls(
            id=row.get("id", ""),
            user_id=row.get("user_id", ""),
            invoice_number=row["invoice_number"],
            created_at=row["created_at"],
            auction_name=row["auction_name"],
            auction_location=row.get("auction_location"),
            viewing_datetime=row.get("viewing_datetime"),
            payment_deadline=row.get("payment_deadline"),
            delivery_type=DeliveryType(row.get("delivery_type", "collection")),
            delivery_method=row.get("delivery_method"),
            items=[
                LotItem(
                    lot_number=i["lot_number"],
                    description=i["description"],
                    hammer_price=Decimal(i["hammer_price_pence"]) / 100,
                    vat=Decimal(i.get("vat_pence", 0)) / 100,
                    subtotal=Decimal(i["subtotal_pence"]) / 100,
                    listing_id=i.get("listing_id"),
                )
                for i in (items or [])
            ],
            items_subtotal=Decimal(row.get("items_subtotal_pence", 0)) / 100,
            delivery_cost=Decimal(row.get("delivery_cost_pence", 0)) / 100,
            buyers_premium=Decimal(row.get("buyers_premium_pence", 0)) / 100,
            total_vat=Decimal(row.get("total_vat_pence", 0)) / 100,
            grand_total=Decimal(row.get("grand_total_pence", 0)) / 100,
            invoice_status=InvoiceStatus(row.get("invoice_status", "new")),
            delivery_status=(
                DeliveryStatus(row["delivery_status"]) if row.get("delivery_status") else None
            ),
            notes=row.get("notes"),
        )
