"""Pydantic schemas for the Cart Plugin module."""
from __future__ import annotations

from datetime import datetime
from typing import Any, Dict, List, Optional

from pydantic import BaseModel, EmailStr, Field, HttpUrl


# ─── Item schemas ─────────────────────────────────────────────────────────────

class CartItemRequest(BaseModel):
    external_id: Optional[str] = None
    name: str = Field(..., max_length=255)
    description: Optional[str] = None
    quantity: int = Field(default=1, ge=1)
    # Accept dollars from the client; convert to cents in service layer.
    unit_price: float = Field(..., ge=0)
    image_url: Optional[str] = Field(default=None, max_length=500)
    metadata: Optional[Dict[str, Any]] = None


class CartItemResponse(BaseModel):
    id: int
    session_id: int
    external_id: Optional[str] = None
    name: str
    description: Optional[str] = None
    quantity: int
    # Return dollars to the client.
    unit_price: float
    image_url: Optional[str] = None
    metadata: Optional[Dict[str, Any]] = None

    class Config:
        from_attributes = True


# ─── Session create ───────────────────────────────────────────────────────────

class CreateCartSessionRequest(BaseModel):
    items: List[CartItemRequest] = Field(..., min_length=1)
    currency: str = Field(default="USD", max_length=10)
    return_url: Optional[str] = Field(default=None, max_length=500)
    checkout_mode: Optional[str] = Field(default=None, max_length=20)
    tip_amount: Optional[float] = Field(default=None, ge=0)
    discount_code: Optional[str] = Field(default=None, max_length=100)
    idempotency_key: Optional[str] = Field(default=None, max_length=128)
    metadata: Optional[Dict[str, Any]] = None
    # Session TTL in minutes; defaults to 60 if not provided.
    ttl_minutes: Optional[int] = Field(default=60, ge=5, le=10080)


class CreateCartSessionResponse(BaseModel):
    token: str
    status: str
    currency: str
    expires_at: Optional[datetime] = None
    items: List[CartItemResponse]
    subtotal: float  # dollars
    checkout_url: str


# ─── Session public response ──────────────────────────────────────────────────

class CartSessionPublicResponse(BaseModel):
    token: str
    status: str
    currency: str
    expires_at: Optional[datetime] = None
    checkout_mode: Optional[str] = None
    return_url: Optional[str] = None
    items: List[CartItemResponse]
    subtotal: float  # dollars
    tip_amount: float  # dollars
    tax_amount: float  # dollars
    discount_amount: float  # dollars
    total: float  # dollars
    discount_code: Optional[str] = None
    merchant_branding: Optional[Dict[str, Any]] = None
    # MED-04: provider_txn_ref removed — only exposed in CartSessionDetailResponse (merchant-auth).


# ─── Discount validation ──────────────────────────────────────────────────────

class ValidateDiscountRequest(BaseModel):
    code: str


class ValidateDiscountResponse(BaseModel):
    valid: bool
    discount_type: Optional[str] = None  # "percentage" | "fixed"
    discount_value: Optional[float] = None
    discount_amount: float = 0.0  # dollars — amount saved on this cart
    message: Optional[str] = None


# ─── Email check ──────────────────────────────────────────────────────────────

class CartEmailCheckRequest(BaseModel):
    email: EmailStr


class CartEmailCheckResponse(BaseModel):
    exists: bool


# ─── Payer auth ───────────────────────────────────────────────────────────────

class CartLoginRequest(BaseModel):
    email: EmailStr
    password: str


class CartRegisterRequest(BaseModel):
    name: str
    email: EmailStr
    password: str = Field(..., min_length=8)


class CartPayerTokenResponse(BaseModel):
    access_token: str
    token_type: str = "bearer"
    customer_id: Optional[int] = None


# ─── Submit ───────────────────────────────────────────────────────────────────

class BillingInfoSchema(BaseModel):
    name: Optional[str] = None
    email: Optional[EmailStr] = None
    phone: Optional[str] = None
    address: Optional[str] = None
    city: Optional[str] = None
    state: Optional[str] = None
    zip: Optional[str] = None
    country: Optional[str] = None


class CartSubmitRequest(BaseModel):
    payment_token: str = Field(..., description="Token from the provider's hosted iframe")
    payment_method_type: str = Field(default="card")
    tip_amount: Optional[float] = Field(default=None, ge=0)
    discount_code: Optional[str] = None
    billing_info: Optional[BillingInfoSchema] = None
    customer_name: Optional[str] = None
    customer_email: Optional[EmailStr] = None


class CartSubmitResponse(BaseModel):
    cart_session_id: int
    provider_txn_ref: str
    amount: float  # dollars
    currency: str
    status: str
    redirect_url: Optional[str] = None


# ─── Iframe config ────────────────────────────────────────────────────────────

class CartIframeConfigResponse(BaseModel):
    sdk_url: str
    api_key: str
    merchant_id: str
    mode: str
    extra: Optional[Dict[str, Any]] = None


# ─── Widget key ───────────────────────────────────────────────────────────────

class CreateWidgetKeyRequest(BaseModel):
    display_name: str = Field(..., max_length=100)
    allowed_origins: Optional[List[str]] = None
    webhook_url: Optional[str] = Field(default=None, max_length=500)
    checkout_mode: str = Field(default="auto", max_length=20)


class UpdateWidgetKeyRequest(BaseModel):
    display_name: Optional[str] = Field(default=None, max_length=100)
    allowed_origins: Optional[List[str]] = None
    webhook_url: Optional[str] = Field(default=None, max_length=500)
    checkout_mode: Optional[str] = Field(default=None, max_length=20)
    is_active: Optional[bool] = None


class WidgetKeyResponse(BaseModel):
    id: int
    merchant_id: int
    display_name: str
    public_key: str
    allowed_origins: Optional[List[str]] = None
    webhook_url: Optional[str] = None
    checkout_mode: str
    is_active: bool
    created_at: datetime
    updated_at: Optional[datetime] = None
    revoked_at: Optional[datetime] = None

    class Config:
        from_attributes = True


class WidgetKeyCreateResponse(WidgetKeyResponse):
    """Returned only at creation / rotation — includes the raw secret once."""
    webhook_secret: Optional[str] = None


class WidgetKeyListResponse(BaseModel):
    items: List[WidgetKeyResponse]
    total: int


# ─── Session list ─────────────────────────────────────────────────────────────

class CartSessionSummary(BaseModel):
    token: str
    status: str
    currency: str
    subtotal: float
    total: float
    customer_email: Optional[str] = None
    created_at: datetime
    expires_at: Optional[datetime] = None

    class Config:
        from_attributes = True


class CartSessionListResponse(BaseModel):
    items: List[CartSessionSummary]
    total: int


# ─── Session detail (merchant view) ──────────────────────────────────────────

class CartSessionDetailResponse(BaseModel):
    token: str
    status: str
    currency: str
    checkout_mode: Optional[str] = None
    origin: Optional[str] = None
    return_url: Optional[str] = None
    customer_name: Optional[str] = None
    customer_email: Optional[str] = None
    billing_info: Optional[Dict[str, Any]] = None
    discount_code: Optional[str] = None
    discount_amount: float
    tip_amount: float
    tax_amount: float
    subtotal: float
    total: float
    transaction_id: Optional[int] = None
    provider_txn_ref: Optional[str] = None
    items: List[CartItemResponse]
    metadata: Optional[Dict[str, Any]] = None
    expires_at: Optional[datetime] = None
    created_at: datetime
    updated_at: Optional[datetime] = None

    class Config:
        from_attributes = True
