# app/modules/billing/schemas/billing.py
"""
Pydantic schemas for billing and subscription operations.

Used for admin subscription management and merchant-level billing.
"""

from datetime import datetime

from pydantic import BaseModel, ConfigDict, Field, field_validator

# ============================================================================
# Subscription Tier Schemas
# ============================================================================


class TierFeatureLimitEntry(BaseModel):
    """Feature limit entry for tier management."""

    feature_code: str
    limit_value: int | None = Field(None, description="None = unlimited for quantitative, ignored for binary")
    enabled: bool = True


class SubscriptionTierBase(BaseModel):
    """Base schema for subscription tier."""

    code: str = Field(..., min_length=1, max_length=30)
    name: str = Field(..., min_length=1, max_length=100)
    description: str | None = None
    price_monthly_cents: int = Field(..., ge=0)
    price_annual_cents: int | None = Field(None, ge=0)
    stripe_product_id: str | None = None
    stripe_price_monthly_id: str | None = None
    stripe_price_annual_id: str | None = None
    display_order: int = 0
    is_active: bool = True
    is_public: bool = True
    platform_id: int | None = None


class SubscriptionTierCreate(SubscriptionTierBase):
    """Schema for creating a subscription tier."""

    feature_limits: list[TierFeatureLimitEntry] = Field(default_factory=list)


class SubscriptionTierUpdate(BaseModel):
    """Schema for updating a subscription tier."""

    name: str | None = None
    description: str | None = None
    price_monthly_cents: int | None = Field(None, ge=0)
    price_annual_cents: int | None = Field(None, ge=0)
    stripe_product_id: str | None = None
    stripe_price_monthly_id: str | None = None
    stripe_price_annual_id: str | None = None
    display_order: int | None = None
    is_active: bool | None = None
    is_public: bool | None = None
    feature_limits: list[TierFeatureLimitEntry] | None = None


class SubscriptionTierResponse(BaseModel):
    """Schema for subscription tier response."""

    model_config = ConfigDict(from_attributes=True)

    id: int
    code: str
    name: str
    description: str | None = None
    price_monthly_cents: int
    price_annual_cents: int | None = None
    platform_id: int | None = None
    platform_name: str | None = None
    stripe_product_id: str | None = None
    stripe_price_monthly_id: str | None = None
    stripe_price_annual_id: str | None = None
    display_order: int
    is_active: bool
    is_public: bool
    feature_codes: list[str] = Field(default_factory=list)
    created_at: datetime
    updated_at: datetime

    @property
    def price_monthly_display(self) -> str:
        """Format monthly price for display."""
        return f"€{self.price_monthly_cents / 100:.2f}"

    @property
    def price_annual_display(self) -> str | None:
        """Format annual price for display."""
        if self.price_annual_cents is None:
            return None
        return f"€{self.price_annual_cents / 100:.2f}"


class SubscriptionTierListResponse(BaseModel):
    """Response for listing subscription tiers."""

    tiers: list[SubscriptionTierResponse]
    total: int


# ============================================================================
# Merchant Subscription Schemas (Admin View)
# ============================================================================


class MerchantSubscriptionAdminResponse(BaseModel):
    """Merchant subscription response for admin views."""

    model_config = ConfigDict(from_attributes=True)

    id: int
    merchant_id: int
    platform_id: int
    tier: str | None = None

    status: str
    is_annual: bool
    period_start: datetime
    period_end: datetime
    trial_ends_at: datetime | None = None

    stripe_customer_id: str | None = None
    stripe_subscription_id: str | None = None

    cancelled_at: datetime | None = None
    cancellation_reason: str | None = None

    payment_retry_count: int = 0
    last_payment_error: str | None = None

    created_at: datetime
    updated_at: datetime

    @field_validator("tier", mode="before")
    @classmethod
    def extract_tier_code(cls, v):
        """Convert SubscriptionTier ORM object to its code string."""
        if v is not None and hasattr(v, "code"):
            return v.code
        return v


class MerchantSubscriptionWithMerchant(MerchantSubscriptionAdminResponse):
    """Subscription response with merchant info."""

    merchant_name: str = ""
    platform_name: str = ""
    tier_name: str | None = None


class MerchantSubscriptionListResponse(BaseModel):
    """Response for listing merchant subscriptions."""

    subscriptions: list[MerchantSubscriptionWithMerchant]
    total: int
    page: int
    per_page: int
    pages: int


class MerchantSubscriptionAdminCreate(BaseModel):
    """Schema for admin creating a merchant subscription."""

    merchant_id: int
    platform_id: int
    tier_code: str = "essential"
    status: str = "trial"
    trial_days: int = 14
    is_annual: bool = False


class MerchantSubscriptionAdminUpdate(BaseModel):
    """Schema for admin updating a merchant subscription."""

    tier_code: str | None = None
    status: str | None = None
    trial_ends_at: datetime | None = None
    cancellation_reason: str | None = None


# ============================================================================
# Merchant Feature Override Schemas
# ============================================================================


class MerchantFeatureOverrideEntry(BaseModel):
    """Feature override for a specific merchant."""

    feature_code: str
    limit_value: int | None = None
    is_enabled: bool = True
    reason: str | None = None


class MerchantFeatureOverrideResponse(BaseModel):
    """Response for merchant feature override."""

    model_config = ConfigDict(from_attributes=True)

    id: int
    merchant_id: int
    platform_id: int
    feature_code: str
    limit_value: int | None = None
    is_enabled: bool
    reason: str | None = None
    created_at: datetime
    updated_at: datetime


# ============================================================================
# Billing History Schemas
# ============================================================================


class BillingHistoryResponse(BaseModel):
    """Schema for billing history entry."""

    model_config = ConfigDict(from_attributes=True)

    id: int
    store_id: int | None = None
    merchant_id: int | None = None
    stripe_invoice_id: str | None = None
    invoice_number: str | None = None
    invoice_date: datetime
    due_date: datetime | None = None

    # Amounts
    subtotal_cents: int
    tax_cents: int
    total_cents: int
    amount_paid_cents: int
    currency: str = "EUR"

    # Status
    status: str

    # URLs
    invoice_pdf_url: str | None = None
    hosted_invoice_url: str | None = None

    # Description
    description: str | None = None

    # Timestamps
    created_at: datetime

    @property
    def total_display(self) -> str:
        """Format total for display."""
        return f"€{self.total_cents / 100:.2f}"


class BillingHistoryWithMerchant(BillingHistoryResponse):
    """Billing history with merchant info."""

    merchant_name: str = ""


class BillingHistoryListResponse(BaseModel):
    """Response for listing billing history."""

    invoices: list[BillingHistoryResponse]
    total: int
    page: int
    per_page: int
    pages: int


# ============================================================================
# Checkout & Portal Schemas
# ============================================================================


class CheckoutRequest(BaseModel):
    """Request for creating checkout session."""

    tier_code: str
    is_annual: bool = False


class CheckoutResponse(BaseModel):
    """Response with checkout session URL."""

    checkout_url: str
    session_id: str


class PortalSessionResponse(BaseModel):
    """Response with customer portal URL."""

    portal_url: str


# ============================================================================
# Subscription Stats Schemas
# ============================================================================


class SubscriptionStatsResponse(BaseModel):
    """Subscription statistics for admin dashboard."""

    total_subscriptions: int
    active_count: int
    trial_count: int
    past_due_count: int
    cancelled_count: int
    expired_count: int

    # By tier
    tier_distribution: dict[str, int]

    # Revenue
    mrr_cents: int  # Monthly recurring revenue
    arr_cents: int  # Annual recurring revenue

    @property
    def mrr_display(self) -> str:
        """Format MRR for display."""
        return f"€{self.mrr_cents / 100:,.2f}"

    @property
    def arr_display(self) -> str:
        """Format ARR for display."""
        return f"€{self.arr_cents / 100:,.2f}"


# ============================================================================
# Feature Catalog Schemas
# ============================================================================


class FeatureDeclarationResponse(BaseModel):
    """Feature declaration for admin display."""

    code: str
    name_key: str
    description_key: str
    category: str
    feature_type: str
    scope: str
    default_limit: int | None = None
    unit_key: str | None = None
    is_per_period: bool = False
    ui_icon: str | None = None
    display_order: int = 0


class FeatureCatalogResponse(BaseModel):
    """All discovered features grouped by category."""

    features: dict[str, list[FeatureDeclarationResponse]]
    total_count: int


# ============================================================================
# Store Checkout Schemas
# ============================================================================


class PortalResponse(BaseModel):
    """Customer portal session response."""

    portal_url: str


class CancelRequest(BaseModel):
    """Request to cancel subscription."""

    reason: str | None = None
    immediately: bool = False


class CancelResponse(BaseModel):
    """Cancellation response."""

    message: str
    effective_date: str


class UpcomingInvoiceResponse(BaseModel):
    """Upcoming invoice preview."""

    amount_due_cents: int
    currency: str
    next_payment_date: str | None = None
    line_items: list[dict] = []


class ChangeTierRequest(BaseModel):
    """Request to change subscription tier."""

    tier_code: str
    is_annual: bool = False


class ChangeTierResponse(BaseModel):
    """Response for tier change."""

    message: str
    new_tier: str
    effective_immediately: bool


# ============================================================================
# Store Subscription Schemas
# ============================================================================


class SubscriptionStatusResponse(BaseModel):
    """Current subscription status."""

    tier_code: str
    tier_name: str
    status: str
    is_trial: bool
    trial_ends_at: str | None = None
    period_start: str | None = None
    period_end: str | None = None
    cancelled_at: str | None = None
    cancellation_reason: str | None = None
    has_payment_method: bool
    last_payment_error: str | None = None
    feature_codes: list[str] = []

    class Config:
        from_attributes = True


class TierResponse(BaseModel):
    """Subscription tier information."""

    code: str
    name: str
    description: str | None = None
    price_monthly_cents: int
    price_annual_cents: int | None = None
    feature_codes: list[str] = []
    is_current: bool = False
    can_upgrade: bool = False
    can_downgrade: bool = False


class TierListResponse(BaseModel):
    """List of available tiers."""

    tiers: list[TierResponse]
    current_tier: str


class InvoiceResponse(BaseModel):
    """Invoice information."""

    id: int
    invoice_number: str | None = None
    invoice_date: str
    due_date: str | None = None
    total_cents: int
    amount_paid_cents: int
    currency: str
    status: str
    pdf_url: str | None = None
    hosted_url: str | None = None


class InvoiceListResponse(BaseModel):
    """List of invoices."""

    invoices: list[InvoiceResponse]
    total: int


# ============================================================================
# Store Feature Schemas
# ============================================================================


class FeatureCodeListResponse(BaseModel):
    """Simple list of available feature codes for quick checks."""

    features: list[str]
    tier_code: str
    tier_name: str


class FeatureResponse(BaseModel):
    """Full feature information."""

    code: str
    name: str
    description: str | None = None
    category: str
    feature_type: str | None = None
    ui_icon: str | None = None
    is_available: bool


class FeatureListResponse(BaseModel):
    """List of features with metadata."""

    features: list[FeatureResponse]
    available_count: int
    total_count: int
    tier_code: str
    tier_name: str


class FeatureDetailResponse(BaseModel):
    """Single feature detail with upgrade info."""

    code: str
    name: str
    description: str | None = None
    category: str
    feature_type: str | None = None
    ui_icon: str | None = None
    is_available: bool
    # Upgrade info (only if not available)
    upgrade_tier_code: str | None = None
    upgrade_tier_name: str | None = None
    upgrade_tier_price_monthly_cents: int | None = None


class CategoryListResponse(BaseModel):
    """List of feature categories."""

    categories: list[str]


class FeatureGroupedResponse(BaseModel):
    """Features grouped by category."""

    categories: dict[str, list[FeatureResponse]]
    available_count: int
    total_count: int


class StoreFeatureCheckResponse(BaseModel):
    """Quick feature availability check response."""

    has_feature: bool
    feature_code: str
