from typing import Literal

from pydantic import BaseModel, Field, model_validator


class PosMemberCreateIn(BaseModel):
    """柜台建会员。姓名和电话必填，邮箱选填——很多顾客当场给不出邮箱。"""
    name: str = Field(min_length=1, max_length=100)
    phone: str = Field(min_length=3, max_length=30)
    email: str | None = None


class PosMemberOut(BaseModel):
    id: int
    name: str
    phone: str | None = None
    tierName: str | None = None
    # True = 手机号/邮箱已存在，返回的是既有会员而不是新建的。
    existing: bool = False


class PosSyncItemIn(BaseModel):
    lineNo: int = Field(ge=1)
    cloudProductId: int = Field(gt=0)
    cloudVariantId: int | None = None
    sku: str | None = None
    barcode: str | None = None
    name: str
    unit: str = "ea"
    quantity: str
    baseUnitPriceCents: int | None = Field(default=None, ge=0)
    listPriceCents: int | None = Field(default=None, ge=0)
    manualUnitPriceCents: int | None = Field(default=None, ge=0)
    unitPriceCents: int = Field(ge=0)
    lineDiscountCents: int = Field(default=0, ge=0)
    lineTotalCents: int = Field(ge=0)
    taxCents: int = Field(ge=0)
    pricesIncludeTax: bool = True
    effectiveTaxRate: str = "0"
    soldByWeight: bool = False
    weightKg: str | None = None


class PosSyncPaymentIn(BaseModel):
    paymentMethod: Literal["cash", "eftpos", "balance"]
    amountCents: int = Field(ge=0)
    tenderedCents: int | None = None
    changeCents: int | None = None
    status: str = "approved"
    provider: str | None = None
    providerTxnRef: str | None = None
    # 脱敏后的 EFTPOS 存根（Agent 已脱敏，绝不含完整卡号/track2）。存入 payments.extra_data 留档。
    eftposReceiptMasked: str | None = None
    # 余额支付：本地已扣款后的 walletTxnId（必须由云端 /pos/wallet/charge 真实写入）。
    # 没有这个值则 amountCents 不能算真正收齐。
    walletTxnId: int | None = None

    @model_validator(mode="after")
    def validate_provider_ref(self):
        if self.paymentMethod == "eftpos" and not self.providerTxnRef:
            raise ValueError("providerTxnRef is required for eftpos payments")
        if self.paymentMethod == "balance" and not self.walletTxnId:
            raise ValueError("walletTxnId is required for balance payments")
        return self


class PosWalletBalanceOut(BaseModel):
    ok: bool
    customerId: int
    balanceCents: int = 0
    currency: str = "NZD"
    reason: str | None = None


class PosWalletChargeIn(BaseModel):
    customerId: int = Field(gt=0)
    amountCents: int = Field(gt=0)
    idempotencyKey: str = Field(min_length=1, max_length=64)
    note: str | None = None


class PosWalletChargeOut(BaseModel):
    ok: bool
    customerId: int
    amountCents: int
    balanceAfterCents: int
    walletTxnId: int | None = None
    duplicate: bool = False
    reason: str | None = None


class PosSyncOrderIn(BaseModel):
    idempotencyKey: str
    clientRequestId: str | None = None
    localOrderNo: str
    tenantId: int = Field(gt=0)
    storeId: int = Field(gt=0)
    laneId: str
    cashierId: int | None = None
    source: Literal["pos"] = "pos"
    createdOffline: bool = True
    memberId: int | None = None
    memberBenefitApplied: bool = False
    quoteToken: str | None = None   # 会员价的云端签名，memberBenefitApplied 时必填
    ageApprovalEvidence: dict | None = None
    priceOverrideApplied: bool = False
    priceOverrideEvidence: dict | None = None
    promotionApplied: bool = False
    promotionDiscountCents: int = Field(default=0, ge=0)
    currency: str = "NZD"
    subtotalCents: int = Field(ge=0)
    discountCents: int = Field(ge=0)
    orderDiscountCents: int = Field(default=0, ge=0)
    taxCents: int = Field(ge=0)
    totalCents: int = Field(ge=0)
    cashRoundingCents: int = 0
    payableCents: int = Field(ge=0)
    items: list[PosSyncItemIn]
    payments: list[PosSyncPaymentIn]
    createdAt: str
    # 小票快照（Agent 从受信模板渲染）随订单上云，供跨机/跨天/90 天后云端兜底重打。
    receiptHtml: str | None = None
    receiptHash: str | None = None
    receiptTemplateKey: str | None = None
    receiptTemplateVersion: str | None = None
    receiptRulesVersion: int | None = None
    printStatus: str | None = None


class PosQuoteItemIn(BaseModel):
    lineNo: int = Field(ge=1)
    cloudProductId: int = Field(gt=0)
    cloudVariantId: int | None = None
    quantity: str


class PosQuoteIn(BaseModel):
    memberId: int = Field(gt=0)
    items: list[PosQuoteItemIn] = Field(min_length=1)


class PosQuoteLineOut(BaseModel):
    lineNo: int
    cloudProductId: int
    cloudVariantId: int | None = None
    quantity: str                      # 进签名：防止 1 件的报价被套用到任意数量
    unitPriceCents: int
    lineTotalCents: int


class PosQuoteOut(BaseModel):
    ok: bool
    memberId: int
    tierName: str | None = None
    lines: list[PosQuoteLineOut] = []
    memberDiscountCents: int = 0
    promoDiscountCents: int = 0
    promoLabel: str | None = None
    quoteToken: str | None = None
    reason: str | None = None


class PosPromoQuoteIn(BaseModel):
    memberId: int | None = None
    items: list[PosQuoteItemIn] = Field(min_length=1)


class PosPromoQuoteOut(BaseModel):
    ok: bool
    promoDiscountCents: int = 0
    promoLabel: str | None = None
    quoteToken: str | None = None
    discountProductIds: list[int] = []
    reason: str | None = None


class PosSyncOrderOut(BaseModel):
    ok: bool
    syncStatus: Literal["synced", "conflict"]
    cloudOrderId: int | None = None
    cloudOrderNo: str | None = None
    reason: str | None = None
