"""Billing domain - Pydantic schemas."""
from __future__ import annotations
from datetime import datetime
from typing import Literal, Optional
from uuid import UUID

from pydantic import BaseModel, EmailStr, Field


class SubscriptionCheckoutCreate(BaseModel):
    """Subscription checkout - internal plan identity only.

    success_url/cancel_url: Optional. When omitted, backend derives from request Origin
    or X-CLIENT-URL / X-CLIENT-DOMAIN headers (must be in APP_URL_WHITELIST).
    When provided, origin must match whitelist. Use for multi-frontend (separate URLs).
    """
    plan_slug: str
    interval: Literal["month", "year"] = "month"
    success_url: Optional[str] = None  # Omit to use Origin/X-CLIENT-* + /billing/success
    cancel_url: Optional[str] = None   # Omit to use Origin/X-CLIENT-* + /billing
    idempotency_key: Optional[str] = Field(default=None, min_length=1, max_length=255)


class UsageTopupCheckoutCreate(BaseModel):
    """One-time usage credit purchase checkout.

    success_url/cancel_url: Optional. Same resolution as SubscriptionCheckoutCreate.
    """
    package_slug: str
    success_url: Optional[str] = None
    cancel_url: Optional[str] = None
    idempotency_key: Optional[str] = Field(default=None, min_length=1, max_length=255)


class CheckoutSessionResponse(BaseModel):
    """Stripe Checkout Session handoff to the frontend.

    For ``plan_slug: "free"``, ``free_plan`` is true and ``checkout_url`` / ``session_id``
    are omitted — do not redirect to Stripe; refresh bootstrap or billing state instead.
    """

    checkout_url: Optional[str] = None
    session_id: Optional[str] = None
    workspace_id: Optional[UUID] = None
    free_plan: bool = False


class SubscriptionResponse(BaseModel):
    id: UUID
    workspace_id: UUID
    stripe_subscription_id: Optional[str] = None
    billing_interval: Optional[str] = None
    status: str
    plan_slug: Optional[str] = None
    plan_id: Optional[str] = None
    plan_name: Optional[str] = None
    current_period_start: Optional[datetime]
    current_period_end: Optional[datetime]
    canceled_at: Optional[datetime]
    trial_end: Optional[datetime]
    # Normalized (set in router via model_copy for OpenAPI stability)
    has_subscription: bool = True
    is_paid: bool = False
    requires_payment: bool = True
    billing_status: Optional[str] = None

    model_config = {"from_attributes": True}


class BillingCheckoutStatusResponse(BaseModel):
    """Poll after Stripe return; 200 + normalized body (no 404 for missing subscription)."""

    workspace_id: UUID
    has_subscription: bool
    status: str
    is_paid: bool
    requires_payment: bool
    plan_slug: Optional[str] = None
    current_period_end: Optional[datetime] = None
    last_checkout_state: str


class InvoiceResponse(BaseModel):
    id: UUID
    workspace_id: UUID
    stripe_invoice_id: str
    status: str
    amount_due: int
    amount_paid: int
    currency: str
    invoice_url: Optional[str]
    invoice_pdf: Optional[str]
    period_start: Optional[datetime]
    period_end: Optional[datetime]
    created_at: datetime

    model_config = {"from_attributes": True}


class UsageSummary(BaseModel):
    event_type: str
    total_quantity: int
    unit_label: Optional[str]
    period_start: Optional[datetime]
    period_end: Optional[datetime]


class CustomerPortalResponse(BaseModel):
    portal_url: str


class CustomerPortalRequest(BaseModel):
    """Optional. When omitted, backend uses Origin/X-CLIENT-* + /billing."""
    return_url: Optional[str] = None


class AvailablePlansResponse(BaseModel):
    """Available plans for workspace (upgrade/downgrade) with current subscription context."""

    plans: list["SubscriptionPlanPublic"]
    current_subscription: Optional[SubscriptionResponse] = None


YearlyPriceSource = Literal["catalog", "estimated_monthly_x12"]


class PlanOfferPublic(BaseModel):
    """Limited-slot campaign price shown next to the (struck-through) catalog price."""

    campaign_slug: str
    price_monthly: Optional[int] = Field(None, description="Campaign monthly price in minor units")
    price_yearly: Optional[int] = Field(None, description="Campaign yearly price in minor units")
    spots_remaining: int


class SubscriptionPlanPublic(BaseModel):
    """Public plan summary for billing UI - no Stripe IDs exposed."""

    id: UUID
    name: str
    slug: str
    description: Optional[str]
    price_monthly: Optional[int] = None
    price_yearly: Optional[int] = None
    yearly_price_source: Optional[YearlyPriceSource] = Field(
        None,
        description="catalog = DB yearly price; estimated_monthly_x12 = 12× monthly if DB yearly unset",
    )
    currency: str
    features: Optional[dict]
    limits: Optional[dict]
    sort_order: int
    trial_days: int
    custom_pricing: bool = False
    offer: Optional[PlanOfferPublic] = None

    model_config = {"from_attributes": True}


class EnterpriseInquiryCreate(BaseModel):
    """Enterprise / custom pricing inquiry (guests allowed)."""

    first_name: str = Field(..., min_length=1, max_length=100)
    last_name: str = Field(..., min_length=1, max_length=100)
    email: EmailStr
    phone: str = Field(..., min_length=1, max_length=50)
    website_count: int = Field(0, ge=0)
    ai_credit_minutes_desired: int = Field(0, ge=0)
    is_agency_account: bool = False
    employee_count: int = Field(0, ge=0)
    additional_features: Optional[str] = Field(None, max_length=8000)
    plan_slug: Optional[str] = Field(None, max_length=50)


class EnterpriseInquiryResponse(BaseModel):
    id: UUID
    message: str = "received"


class UsageCreditPackagePublic(BaseModel):
    slug: str
    name: str
    description: Optional[str] = None
    units: int
    price_minor: int
    currency: str


class WorkspaceBalanceResponse(BaseModel):
    included_remaining: int
    topup_remaining: int
    total_available: int
    has_active_subscription: bool
    plan_slug: Optional[str] = None
    packages: list[UsageCreditPackagePublic]
