"""Sales response schemas."""
from datetime import datetime
from decimal import Decimal
from typing import Dict, List, Optional
from uuid import UUID
from pydantic import BaseModel, ConfigDict


class OpportunityResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: UUID
    tenant_id: UUID
    family_name: Optional[str] = None
    care_type: Optional[str] = None
    contact_phone: Optional[str] = None
    contact_email: Optional[str] = None
    section_id: Optional[UUID] = None
    plot_id: Optional[UUID] = None
    estimated_value: Optional[Decimal] = None
    assigned_to: Optional[UUID] = None
    stage: str
    stage_entered_at: Optional[datetime] = None
    next_action: Optional[str] = None
    lost_reason: Optional[str] = None
    lost_notes: Optional[str] = None
    lost_at: Optional[datetime] = None
    lost_from_stage: Optional[str] = None
    notes: Optional[str] = None
    deleted_at: Optional[datetime] = None
    created_at: datetime
    updated_at: datetime
    days_in_stage: int = 0


class KanbanResponse(BaseModel):
    inquiry: List[Dict] = []
    site_visit: List[Dict] = []
    proposal_sent: List[Dict] = []
    proposal_accepted: List[Dict] = []
    contract_sent: List[Dict] = []
    contract_signed: List[Dict] = []
    deposit_received: List[Dict] = []  # kept for backward compat
    partial_payment_received: List[Dict] = []
    fully_paid: List[Dict] = []
    lost: List[Dict] = []


class ProposalLineItemResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: UUID
    sort_order: int
    description: str
    quantity: Decimal
    unit_price: Decimal
    line_total: Decimal


class ProposalResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: UUID
    tenant_id: UUID
    opportunity_id: Optional[UUID] = None
    quote_number: str
    to_email: str
    cc_email: Optional[str] = None
    subject: str
    cover_note: Optional[str] = None
    valid_days: int
    sales_owner_id: Optional[UUID] = None
    status: str
    subtotal: Decimal
    tax_rate: Decimal
    tax_amount: Decimal
    total_amount: Decimal
    sent_at: Optional[datetime] = None
    accepted_at: Optional[datetime] = None
    declined_at: Optional[datetime] = None
    expires_at: Optional[datetime] = None
    # pdf_s3_key intentionally omitted — raw S3 key must not leave the server
    deleted_at: Optional[datetime] = None
    created_at: datetime
    updated_at: datetime
    line_items: List[ProposalLineItemResponse] = []
    is_expired: bool = False


class ContractLineItemResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: UUID
    description: str
    fee_type: Optional[str] = None
    quantity: int
    unit_price: Decimal
    line_total: Decimal


class ContractResponse(BaseModel):
    """List-safe contract representation.

    Intentionally excludes:
    - ``purchaser_signature_b64`` — potentially hundreds of KB per row; never
      needed in a paginated list.
    - ``pdf_s3_key`` — raw S3 object key must never be exposed to clients;
      callers should request a presigned URL through a dedicated endpoint.
    """

    model_config = ConfigDict(from_attributes=True)

    id: UUID
    tenant_id: UUID
    contract_number: str
    opportunity_id: Optional[UUID] = None
    plot_id: Optional[UUID] = None
    plot_ref: Optional[str] = None
    section_id: Optional[UUID] = None
    created_by: Optional[UUID] = None
    contract_type: Optional[str] = None
    status: str
    purchaser_id: Optional[UUID] = None
    purchaser_name: Optional[str] = None
    purchaser_email: Optional[str] = None
    purchaser_phone: Optional[str] = None
    purchaser_address: Optional[str] = None
    payment_plan_type: Optional[str] = None
    deposit_amount: Optional[Decimal] = None
    payment_schedule: Optional[dict] = None
    total_amount: Decimal = Decimal("0")
    # NOTE: purchaser_signature_b64 deliberately omitted — use ContractDetailResponse
    witness_name: Optional[str] = None
    signed_at: Optional[datetime] = None
    # NOTE: pdf_s3_key deliberately omitted — raw S3 key must not leave the server
    pdf_available: bool = False  # True once a PDF has been generated; clients poll this
    # NOTE: signed_document_s3_key deliberately omitted — raw S3 key must not leave the server
    signed_document_available: bool = False  # True once a staff-uploaded signed PDF exists
    deleted_at: Optional[datetime] = None
    created_at: datetime
    updated_at: datetime
    line_items: List[ContractLineItemResponse] = []

    @classmethod
    def from_orm_list(cls, contract: object) -> "ContractResponse":
        """Build a list-safe response, deriving ``pdf_available`` and ``plot_ref`` from the ORM object."""
        obj = cls.model_validate(contract)
        # pdf_s3_key is not in the schema; read it directly from the ORM object
        obj.pdf_available = bool(getattr(contract, "pdf_s3_key", None))
        obj.signed_document_available = bool(
            getattr(contract, "signed_document_s3_key", None)
        )
        # Eagerly-loaded plot relationship → human-readable plot reference
        plot = getattr(contract, "plot", None)
        if plot is not None:
            obj.plot_ref = getattr(plot, "plot_ref", None)
        return obj


class ContractDetailResponse(ContractResponse):
    """Full contract detail including the signature blob.

    Only returned by ``GET /contracts/{id}``.  Never used in list responses to
    avoid serialising large base64 payloads for every row in a paginated table.
    The raw ``pdf_s3_key`` is still omitted; use the presigned-URL endpoint.
    """

    purchaser_signature_b64: Optional[str] = None
    payment_token: Optional[str] = None
    payment_link_url: Optional[str] = None
    contract_sent_at: Optional[datetime] = None
    contract_email_sent_to: Optional[str] = None


class IssuedInvoiceInfo(BaseModel):
    id: UUID
    amount: Decimal
    due_date: Optional[str] = None
    label: str


class ContractIssueResponse(BaseModel):
    contract_id: UUID
    contract_number: str
    email_sent_to: Optional[str] = None
    payment_link_url: str
    invoices_created: List[IssuedInvoiceInfo] = []
    opportunity_stage_updated_to: Optional[str] = None
