"""
Schemas for Billing, Invoices, Discount Rules, and Payments.
"""

from datetime import datetime
from decimal import Decimal
from uuid import UUID

from pydantic import BaseModel, ConfigDict, Field, model_validator

from app.models.billing import BillStatus, DiscountType, PaymentMode

# ── Discount Rule Schemas ──────────────────────────────────────────────────────


class DiscountRuleBase(BaseModel):
    """Base fields for discount rules."""

    name: str = Field(..., min_length=1, max_length=100, description="Rule name")
    code: str | None = Field(None, max_length=30, description="Short discount code")
    discount_type: DiscountType = Field(
        default=DiscountType.PERCENTAGE,
        description="Calculation type: percentage or fixed",
    )
    discount_value: Decimal = Field(
        ...,
        description="Percentage value (e.g. 10.00) or fixed amount (e.g. 500.00)",
    )
    is_active: bool = Field(default=True, description="Active status")
    description: str | None = Field(None, description="Internal remarks")


class DiscountRuleCreate(DiscountRuleBase):
    """Payload to create a new branch discount rule."""

    @model_validator(mode="after")
    def validate_discount_value(self) -> "DiscountRuleCreate":
        if self.discount_type == DiscountType.PERCENTAGE:
            if self.discount_value <= Decimal("0.00") or self.discount_value > Decimal("100.00"):
                raise ValueError("Percentage discount must be between 0.01 and 100.00")
        elif self.discount_type == DiscountType.FIXED:
            if self.discount_value <= Decimal("0.00"):
                raise ValueError("Fixed discount amount must be greater than 0.00")
        return self


class DiscountRuleUpdate(BaseModel):
    """Payload to update an existing discount rule."""

    name: str | None = Field(None, min_length=1, max_length=100)
    code: str | None = Field(None, max_length=30)
    discount_type: DiscountType | None = None
    discount_value: Decimal | None = None
    is_active: bool | None = None
    description: str | None = None

    @model_validator(mode="after")
    def validate_discount_value(self) -> "DiscountRuleUpdate":
        if self.discount_value is not None:
            if self.discount_value <= Decimal("0.00"):
                raise ValueError("Discount value must be greater than 0.00")
            if self.discount_type == DiscountType.PERCENTAGE and self.discount_value > Decimal("100.00"):
                raise ValueError("Percentage discount cannot exceed 100.00")
        return self


class DiscountRuleResponse(BaseModel):
    """Response representation of a discount rule."""

    id: UUID
    lab_id: UUID
    name: str
    code: str | None
    discount_type: DiscountType
    discount_value: Decimal
    is_active: bool
    description: str | None
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


# ── Bill Schemas ───────────────────────────────────────────────────────────────


class BillCreate(BaseModel):
    """Payload to generate an invoice for a visit order."""

    order_id: UUID = Field(..., description="Target visit order ID (must not already have an active bill)")
    discount_rule_id: UUID | None = Field(None, description="Optional discount rule from the same branch")
    manual_discount_amount: Decimal | None = Field(
        None,
        ge=Decimal("0.00"),
        description="Manual lump-sum discount (used only if discount_rule_id is None)",
    )
    tax_amount: Decimal = Field(
        default=Decimal("0.00"),
        ge=Decimal("0.00"),
        description="Applicable tax/VAT amount (default 0.00)",
    )
    notes: str | None = Field(None, max_length=1000, description="Billing remarks or terms")

    @model_validator(mode="after")
    def validate_discount_exclusivity(self) -> "BillCreate":
        if self.discount_rule_id is not None and self.manual_discount_amount is not None:
            raise ValueError("Provide either discount_rule_id or manual_discount_amount, not both.")
        return self


class BillUpdate(BaseModel):
    """Payload to update billing remarks or notes."""

    notes: str | None = Field(None, max_length=1000)


class BillVoidRequest(BaseModel):
    """Payload to void an invoice."""

    reason: str = Field(..., min_length=3, max_length=500, description="Audit reason for voiding")


class BillResponse(BaseModel):
    """Standard invoice summary response."""

    id: UUID
    lab_id: UUID
    order_id: UUID
    patient_id: UUID
    bill_number: str
    status: BillStatus
    subtotal: Decimal
    discount_amount: Decimal
    discount_rule_id: UUID | None
    tax_amount: Decimal
    total_amount: Decimal
    paid_amount: Decimal
    due_amount: Decimal
    destination_country: str | None = None
    is_abroad: bool = False
    notes: str | None
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class PaymentCreate(BaseModel):
    """Payload to record a payment transaction against an invoice."""

    amount: Decimal = Field(..., gt=Decimal("0.00"), description="Payment tender amount")
    payment_mode: PaymentMode = Field(default=PaymentMode.CASH, description="Tender mode")
    transaction_reference: str | None = Field(None, max_length=100, description="Card/mobile transaction ref")
    notes: str | None = Field(None, max_length=500, description="Cashier remarks")


class PaymentResponse(BaseModel):
    """Response representation of a payment receipt."""

    id: UUID
    lab_id: UUID
    bill_id: UUID
    received_by: UUID | None
    amount: Decimal
    payment_mode: PaymentMode
    transaction_reference: str | None
    paid_at: datetime
    notes: str | None
    created_at: datetime
    updated_at: datetime
    received_by_name: str | None = None

    model_config = ConfigDict(from_attributes=True)


class BillSampleItem(BaseModel):
    """Specimen generated under the billed visit order."""

    sample_code: str
    barcode: str
    sample_type: str
    status: str

    model_config = ConfigDict(from_attributes=True)


class BillDetailResponse(BillResponse):
    """Detailed invoice response with order summary, patient info, and payment receipts."""

    patient_name: str | None = None
    patient_mrn: str | None = None
    patient_phone: str | None = None
    order_number: str | None = None
    discount_rule_name: str | None = None
    portal_pin: str | None = Field(
        None,
        description="One-time 6-digit client portal PIN (only returned when a new bill is created)",
    )
    payments: list[PaymentResponse] = []
    samples: list[BillSampleItem] = Field(default_factory=list)
