"""Billing models for vikdata API.

ALL field names use snake_case to match the backend API.

NOTE: Types like tier, pricing_model, status are stored as strings.
Valid values come from database lookup tables, not hardcoded enums.
"""

from datetime import datetime
from typing import Any
from uuid import UUID

from pydantic import BaseModel, Field


# =============================================================================
# Plan Series
# =============================================================================


class PlanSeries(BaseModel):
    """Plan series response model."""

    id: UUID = Field(..., description="Series ID")
    name: str = Field(..., description="Series name")
    slug: str = Field(..., description="URL-friendly slug")
    description: str | None = Field(default=None, description="Series description")
    default_max_cores: int = Field(..., description="Default max cores")
    default_max_channels_per_core: int = Field(..., description="Default max channels per core")
    default_max_destinations: int = Field(..., description="Default max destinations")
    default_max_replicas_per_core: int = Field(..., description="Default max replicas per core")
    default_cpu_millicores_per_replica: int = Field(..., description="Default CPU millicores")
    default_memory_mb_per_replica: int = Field(..., description="Default memory MB")
    service_id: UUID | None = Field(default=None, description="Associated service ID")
    is_public: bool = Field(..., description="Whether series is publicly available")
    display_order: int = Field(..., description="Display order")
    resource_mode: str = Field(..., description="Resource provisioning mode (from lookup)")
    created_at: datetime = Field(..., description="Creation timestamp")
    updated_at: datetime = Field(..., description="Last update timestamp")


# =============================================================================
# Plans
# =============================================================================


class ResourceLimits(BaseModel):
    """Resource limits configuration."""

    max_cores: int | None = Field(default=None, description="Max cores")
    max_channels_per_core: int | None = Field(default=None, description="Max channels per core")
    max_destinations: int | None = Field(default=None, description="Max destinations")
    max_replicas_per_core: int | None = Field(default=None, description="Max replicas per core")
    cpu_millicores_per_replica: int | None = Field(default=None, description="CPU millicores")
    memory_mb_per_replica: int | None = Field(default=None, description="Memory MB")


class UsagePricingConfig(BaseModel):
    """Usage pricing configuration."""

    included: int = Field(..., description="Included units")
    overage_rate: int = Field(..., description="Overage rate in cents per unit")


class Plan(BaseModel):
    """Plan response model."""

    id: UUID = Field(..., description="Plan ID")
    series_id: UUID = Field(..., description="Parent series ID")
    name: str = Field(..., description="Plan name")
    slug: str = Field(..., description="URL-friendly slug")
    description: str | None = Field(default=None, description="Plan description")
    tier: str = Field(..., description="Plan tier (from lookup)")
    pricing_model: str = Field(..., description="Pricing model (from lookup)")
    price_monthly: int = Field(..., ge=0, description="Monthly price in cents")
    price_yearly: int = Field(..., ge=0, description="Yearly price in cents")
    usage_pricing: dict[str, UsagePricingConfig] | None = Field(default=None, description="Usage pricing")
    resource_limits: ResourceLimits | None = Field(default=None, description="Resource limits")
    features: dict[str, Any] | None = Field(default=None, description="Feature flags")
    is_public: bool = Field(..., description="Whether plan is publicly available")
    trial_days: int = Field(..., ge=0, description="Trial period in days")
    display_order: int = Field(..., description="Display order")
    created_at: datetime = Field(..., description="Creation timestamp")
    updated_at: datetime = Field(..., description="Last update timestamp")


# =============================================================================
# Subscriptions
# =============================================================================


class Subscription(BaseModel):
    """Subscription response model."""

    id: UUID = Field(..., description="Subscription ID")
    tenant_id: UUID = Field(..., description="Tenant ID")
    plan_id: UUID = Field(..., description="Plan ID")
    series_id: UUID = Field(..., description="Series ID")
    status: str = Field(..., description="Subscription status (from lookup)")
    billing_cycle: str = Field(..., description="Billing cycle (monthly/yearly)")
    provider: str | None = Field(default=None, description="Payment provider")
    provider_customer_id: str | None = Field(default=None, description="Provider customer ID")
    provider_subscription_id: str | None = Field(default=None, description="Provider subscription ID")
    current_period_start: datetime | None = Field(default=None, description="Current period start")
    current_period_end: datetime | None = Field(default=None, description="Current period end")
    trial_ends_at: datetime | None = Field(default=None, description="Trial end date")
    canceled_at: datetime | None = Field(default=None, description="Cancellation date")
    cancel_at_period_end: bool = Field(..., description="Cancel at period end")
    plan: Plan | None = Field(default=None, description="Expanded plan")
    series: PlanSeries | None = Field(default=None, description="Expanded series")
    created_at: datetime = Field(..., description="Creation timestamp")
    updated_at: datetime = Field(..., description="Last update timestamp")


class CreateSubscriptionRequest(BaseModel):
    """Create subscription request."""

    plan_id: UUID = Field(..., description="Plan ID")
    billing_cycle: str | None = Field(default=None, description="Billing cycle (monthly/yearly)")
    trial_days: int | None = Field(default=None, ge=0, description="Trial period in days")


class UpdateSubscriptionRequest(BaseModel):
    """Update subscription request (plan change)."""

    plan_id: UUID = Field(..., description="New plan ID")


class CancelSubscriptionRequest(BaseModel):
    """Cancel subscription request."""

    at_period_end: bool = Field(default=True, description="Cancel at end of period")


# =============================================================================
# Series Quotas
# =============================================================================


class SeriesQuota(BaseModel):
    """Series quota response model."""

    id: UUID = Field(..., description="Quota ID")
    tenant_id: UUID = Field(..., description="Tenant ID")
    series_id: UUID = Field(..., description="Series ID")
    subscription_id: UUID = Field(..., description="Subscription ID")
    plan_id: UUID = Field(..., description="Plan ID")
    # Plan base quotas
    plan_max_cores: int = Field(..., description="Plan max cores")
    plan_max_channels_per_core: int = Field(..., description="Plan max channels per core")
    plan_max_destinations: int = Field(..., description="Plan max destinations")
    plan_max_replicas_per_core: int = Field(..., description="Plan max replicas per core")
    plan_cpu_millicores_per_replica: int = Field(..., description="Plan CPU millicores")
    plan_memory_mb_per_replica: int = Field(..., description="Plan memory MB")
    # Additional quotas from approved requests
    additional_cores: int = Field(..., description="Additional cores")
    additional_channels_per_core: int = Field(..., description="Additional channels per core")
    additional_destinations: int = Field(..., description="Additional destinations")
    additional_replicas_per_core: int = Field(..., description="Additional replicas per core")
    additional_cpu_millicores_per_replica: int = Field(..., description="Additional CPU")
    additional_memory_mb_per_replica: int = Field(..., description="Additional memory")
    # Effective quotas (computed)
    effective_max_cores: int = Field(..., description="Effective max cores")
    effective_max_channels_per_core: int = Field(..., description="Effective max channels")
    effective_max_destinations: int = Field(..., description="Effective max destinations")
    effective_max_replicas_per_core: int = Field(..., description="Effective max replicas")
    effective_cpu_millicores_per_replica: int = Field(..., description="Effective CPU")
    effective_memory_mb_per_replica: int = Field(..., description="Effective memory")
    # Current usage
    current_cores: int = Field(default=0, description="Current cores in use")
    current_destinations: int = Field(default=0, description="Current destinations in use")
    # Expanded series
    series: PlanSeries | None = Field(default=None, description="Expanded series")
    created_at: datetime = Field(..., description="Creation timestamp")
    updated_at: datetime = Field(..., description="Last update timestamp")


# =============================================================================
# Quota Requests
# =============================================================================


class QuotaRequest(BaseModel):
    """Quota request response model."""

    id: UUID = Field(..., description="Request ID")
    tenant_id: UUID = Field(..., description="Tenant ID")
    series_quota_id: UUID = Field(..., description="Series quota ID")
    series_id: UUID = Field(..., description="Series ID")
    requested_additional_cores: int | None = Field(default=None, description="Requested additional cores")
    requested_additional_channels_per_core: int | None = Field(default=None, description="Requested channels")
    requested_additional_destinations: int | None = Field(default=None, description="Requested destinations")
    requested_additional_replicas_per_core: int | None = Field(default=None, description="Requested replicas")
    requested_additional_cpu_millicores_per_replica: int | None = Field(default=None, description="Requested CPU")
    requested_additional_memory_mb_per_replica: int | None = Field(default=None, description="Requested memory")
    justification: str | None = Field(default=None, description="Request justification")
    status: str = Field(..., description="Request status (from lookup)")
    requested_by_id: UUID | None = Field(default=None, description="Requester user ID")
    reviewed_by_id: UUID | None = Field(default=None, description="Reviewer user ID")
    reviewed_at: datetime | None = Field(default=None, description="Review timestamp")
    review_notes: str | None = Field(default=None, description="Review notes")
    series: PlanSeries | None = Field(default=None, description="Expanded series")
    created_at: datetime = Field(..., description="Creation timestamp")
    updated_at: datetime = Field(..., description="Last update timestamp")


class CreateQuotaRequestModel(BaseModel):
    """Create quota request."""

    series_id: UUID = Field(..., description="Series ID")
    requested_additional_cores: int | None = Field(default=None, gt=0, description="Additional cores")
    requested_additional_channels_per_core: int | None = Field(default=None, gt=0, description="Additional channels")
    requested_additional_destinations: int | None = Field(default=None, gt=0, description="Additional destinations")
    requested_additional_replicas_per_core: int | None = Field(default=None, gt=0, description="Additional replicas")
    requested_additional_cpu_millicores_per_replica: int | None = Field(default=None, gt=0, description="Additional CPU")
    requested_additional_memory_mb_per_replica: int | None = Field(default=None, gt=0, description="Additional memory")
    justification: str = Field(..., min_length=10, max_length=2000, description="Justification")


class ReviewQuotaRequestModel(BaseModel):
    """Review quota request."""

    status: str = Field(..., description="New status (from lookup: approved/rejected)")
    review_notes: str | None = Field(default=None, max_length=2000, description="Review notes")


# =============================================================================
# Usage
# =============================================================================


class UsageSummary(BaseModel):
    """Usage summary response model."""

    series_id: UUID = Field(..., description="Series ID")
    billing_period_start: datetime = Field(..., description="Billing period start")
    billing_period_end: datetime = Field(..., description="Billing period end")
    usage: dict[str, float] = Field(..., description="Usage by metric")
    included: dict[str, float] = Field(..., description="Included by metric")
    overage: dict[str, float] = Field(..., description="Overage by metric")
    overage_charges: dict[str, int] = Field(..., description="Overage charges in cents")
    total_overage_cents: int = Field(..., description="Total overage in cents")


# =============================================================================
# Invoices
# =============================================================================


class InvoiceLineItem(BaseModel):
    """Invoice line item."""

    description: str = Field(..., description="Line item description")
    quantity: float = Field(..., description="Quantity")
    unit_price: int = Field(..., description="Unit price in cents")
    amount: int = Field(..., description="Total amount in cents")


class Invoice(BaseModel):
    """Invoice response model."""

    id: UUID = Field(..., description="Invoice ID")
    tenant_id: UUID = Field(..., description="Tenant ID")
    subscription_id: UUID = Field(..., description="Subscription ID")
    invoice_number: str = Field(..., description="Invoice number")
    billing_period_start: datetime = Field(..., description="Billing period start")
    billing_period_end: datetime = Field(..., description="Billing period end")
    base_amount: int = Field(..., description="Base amount in cents")
    overage_amount: int = Field(..., description="Overage amount in cents")
    total_amount: int = Field(..., description="Total amount in cents")
    currency: str = Field(..., description="Currency code")
    line_items: list[InvoiceLineItem] = Field(..., description="Line items")
    status: str = Field(..., description="Invoice status (from lookup)")
    due_at: datetime | None = Field(default=None, description="Due date")
    paid_at: datetime | None = Field(default=None, description="Payment date")
    provider_invoice_id: str | None = Field(default=None, description="Provider invoice ID")
    created_at: datetime = Field(..., description="Creation timestamp")
    updated_at: datetime = Field(..., description="Last update timestamp")


# =============================================================================
# Checkout/Portal
# =============================================================================


class CheckoutSessionRequest(BaseModel):
    """Checkout session request."""

    plan_id: UUID = Field(..., description="Plan ID")
    success_url: str = Field(..., description="Success redirect URL")
    cancel_url: str = Field(..., description="Cancel redirect URL")


class CheckoutSessionResponse(BaseModel):
    """Checkout session response."""

    checkout_url: str = Field(..., description="Checkout URL")


class BillingPortalResponse(BaseModel):
    """Billing portal response."""

    portal_url: str | None = Field(default=None, description="Portal URL (null for stub provider)")
    message: str | None = Field(default=None, description="Message for user")


# =============================================================================
# Query Parameters
# =============================================================================


class ListPlansParams(BaseModel):
    """Query parameters for listing plans."""

    series_id: UUID | None = Field(default=None, description="Filter by series")
    tier: str | None = Field(default=None, description="Filter by tier (from lookup)")
    is_public: bool | None = Field(default=None, description="Filter by public status")


class QuotaRequestListParams(BaseModel):
    """Query parameters for listing quota requests."""

    page: int | None = Field(default=1, ge=1, description="Page number")
    per_page: int | None = Field(default=20, ge=1, le=100, description="Items per page")
    series_id: UUID | None = Field(default=None, description="Filter by series")
    status: str | None = Field(default=None, description="Filter by status (from lookup)")
