# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""Billing models: BillingAccount, BillingTransaction, BillingSettings, UsageStatistics."""

from typing import List, Dict, Any, Optional
from enum import Enum
from datetime import date, datetime, timezone
from pydantic import BaseModel, Field
from modules.datamodels.datamodelBase import PowerOnModel
from modules.shared.i18nRegistry import i18nModel
import uuid

# End-customer price for storage above plan-included volume (CHF per GB per month).
STORAGE_PRICE_PER_GB_CHF = 0.50


class TransactionTypeEnum(str, Enum):
    """Transaction types for billing."""
    CREDIT = "CREDIT"         # Credit/top-up (positive)
    DEBIT = "DEBIT"           # Debit/usage (positive amount, reduces balance)
    ADJUSTMENT = "ADJUSTMENT" # Manual adjustment by admin


class ReferenceTypeEnum(str, Enum):
    """Reference types for transactions."""
    WORKFLOW = "WORKFLOW"   # AI workflow usage
    PAYMENT = "PAYMENT"     # Payment/top-up
    ADMIN = "ADMIN"         # Admin adjustment
    SYSTEM = "SYSTEM"       # System credit (e.g., initial credit)
    STORAGE = "STORAGE"     # Metered storage overage (prepay pool)
    SUBSCRIPTION = "SUBSCRIPTION"  # AI budget credit from subscription plan


class PeriodTypeEnum(str, Enum):
    """Period types for usage statistics."""
    DAY = "DAY"
    MONTH = "MONTH"
    YEAR = "YEAR"


@i18nModel("Abrechnungskonto")
class BillingAccount(PowerOnModel):
    """Billing account for mandate or user-mandate combination."""
    id: str = Field(
        default_factory=lambda: str(uuid.uuid4()),
        description="Primary key",
        json_schema_extra={"label": "ID"},
    )
    mandateId: str = Field(..., description="Foreign key to Mandate", json_schema_extra={"label": "Mandanten-ID"})
    userId: Optional[str] = Field(
        None,
        description="Foreign key to User (None = mandate pool account, set = user audit account)",
        json_schema_extra={"label": "Benutzer-ID"},
    )
    balance: float = Field(default=0.0, description="Current balance in CHF", json_schema_extra={"label": "Guthaben (CHF)"})
    warningThreshold: float = Field(
        default=0.0,
        description="Warning threshold in CHF",
        json_schema_extra={"label": "Warnschwelle (CHF)"},
    )
    lastWarningAt: Optional[datetime] = Field(
        None,
        description="Last warning sent timestamp",
        json_schema_extra={"label": "Letzte Warnung"},
    )
    enabled: bool = Field(default=True, description="Account is active", json_schema_extra={"label": "Aktiv"})


@i18nModel("Transaktion")
class BillingTransaction(PowerOnModel):
    """Single billing transaction (credit, debit, adjustment)."""
    id: str = Field(
        default_factory=lambda: str(uuid.uuid4()),
        description="Primary key",
        json_schema_extra={"label": "ID"},
    )
    accountId: str = Field(..., description="Foreign key to BillingAccount", json_schema_extra={"label": "Konto-ID"})
    transactionType: TransactionTypeEnum = Field(..., description="Transaction type", json_schema_extra={"label": "Typ"})
    amount: float = Field(..., description="Amount in CHF (always positive)", json_schema_extra={"label": "Betrag (CHF)"})
    description: str = Field(..., description="Transaction description", json_schema_extra={"label": "Beschreibung"})

    # Reference to source
    referenceType: Optional[ReferenceTypeEnum] = Field(None, description="Reference type", json_schema_extra={"label": "Referenztyp"})
    referenceId: Optional[str] = Field(None, description="Reference ID", json_schema_extra={"label": "Referenz-ID"})

    # Context for workflow transactions
    workflowId: Optional[str] = Field(None, description="Workflow ID (for WORKFLOW transactions)", json_schema_extra={"label": "Workflow-ID"})
    featureInstanceId: Optional[str] = Field(None, description="Feature instance ID", json_schema_extra={"label": "Feature-Instanz-ID"})
    featureCode: Optional[str] = Field(None, description="Feature code (e.g., automation)", json_schema_extra={"label": "Feature-Code"})
    aicoreProvider: Optional[str] = Field(None, description="AICore provider (anthropic, openai, etc.)", json_schema_extra={"label": "AI-Anbieter"})
    aicoreModel: Optional[str] = Field(None, description="AICore model name (e.g., claude-4-sonnet, gpt-4o)", json_schema_extra={"label": "AI-Modell"})
    createdByUserId: Optional[str] = Field(None, description="User who created/caused this transaction", json_schema_extra={"label": "Erstellt von Benutzer"})

    # AI call metadata (for per-call analytics)
    processingTime: Optional[float] = Field(None, description="Processing time in seconds", json_schema_extra={"label": "Verarbeitungszeit (s)"})
    bytesSent: Optional[int] = Field(None, description="Bytes sent to AI model", json_schema_extra={"label": "Gesendete Bytes"})
    bytesReceived: Optional[int] = Field(None, description="Bytes received from AI model", json_schema_extra={"label": "Empfangene Bytes"})
    errorCount: Optional[int] = Field(None, description="Number of errors in this call", json_schema_extra={"label": "Fehleranzahl"})


@i18nModel("Abrechnungseinstellungen")
class BillingSettings(BaseModel):
    """Billing settings per mandate. Only PREPAY_MANDATE model."""
    id: str = Field(
        default_factory=lambda: str(uuid.uuid4()),
        description="Primary key",
        json_schema_extra={"label": "ID"},
    )
    mandateId: str = Field(..., description="Foreign key to Mandate (UNIQUE)", json_schema_extra={"label": "Mandanten-ID"})

    warningThresholdPercent: float = Field(
        default=10.0,
        description="Warning threshold as percentage",
        json_schema_extra={"label": "Warnschwelle (%)"},
    )

    # Stripe
    stripeCustomerId: Optional[str] = Field(
        None,
        description="Stripe Customer ID (cus_xxx) — one per mandate",
        json_schema_extra={"label": "Stripe-Kunden-ID"},
    )

    # Auto-Recharge for AI budget
    autoRechargeEnabled: bool = Field(default=False, description="Auto-buy AI budget when low", json_schema_extra={"label": "Auto-Nachladung"})
    rechargeAmountCHF: float = Field(
        default=10.0,
        description="Amount per auto-recharge (CHF, prepaid via Stripe)",
        json_schema_extra={"label": "Nachladebetrag (CHF)"},
    )
    rechargeMaxPerMonth: int = Field(default=3, description="Max auto-recharges per month", json_schema_extra={"label": "Max. Nachladungen/Monat"})
    rechargesThisMonth: int = Field(default=0, description="Counter: auto-recharges used this month", json_schema_extra={"label": "Nachladungen diesen Monat"})
    monthResetAt: Optional[datetime] = Field(None, description="When rechargesThisMonth was last reset", json_schema_extra={"label": "Monats-Reset"})

    # Notifications
    notifyEmails: List[str] = Field(
        default_factory=list,
        description="Email addresses for billing alerts (pool exhausted, warnings, etc.)",
        json_schema_extra={"label": "E-Mails fuer Billing-Alerts (Inhaber/Admin)"},
    )
    notifyOnWarning: bool = Field(default=True, description="Send email when warning threshold is reached", json_schema_extra={"label": "Bei Warnung benachrichtigen"})

    # Storage overage (high-watermark within subscription period; resets on new period)
    storageHighWatermarkMB: float = Field(
        default=0.0,
        description="Peak indexed data volume MB this billing period",
        json_schema_extra={"label": "Speicher-Peak (MB)"},
    )
    storagePeriodStartAt: Optional[datetime] = Field(
        None,
        description="Subscription billing period start used for storage reset",
        json_schema_extra={"label": "Speicher-Periodenbeginn"},
    )
    storageBilledUpToMB: float = Field(
        default=0.0,
        description="Overage MB already debited this period (above plan-included volume)",
        json_schema_extra={"label": "Speicher abgerechneter Überhang (MB)"},
    )


class StripeWebhookEvent(BaseModel):
    """Stores processed Stripe webhook event IDs for idempotency."""
    id: str = Field(
        default_factory=lambda: str(uuid.uuid4()),
        description="Primary key",
    )
    event_id: str = Field(..., description="Stripe event ID (evt_xxx)")
    processed_at: datetime = Field(
        default_factory=lambda: datetime.now(timezone.utc),
        description="When the event was processed",
    )


@i18nModel("Nutzungsstatistik")
class UsageStatistics(BaseModel):
    """Aggregated usage statistics for quick retrieval."""
    id: str = Field(
        default_factory=lambda: str(uuid.uuid4()),
        description="Primary key",
        json_schema_extra={"label": "ID"},
    )
    accountId: str = Field(..., description="Foreign key to BillingAccount", json_schema_extra={"label": "Konto-ID"})
    periodType: PeriodTypeEnum = Field(..., description="Period type", json_schema_extra={"label": "Periodentyp"})
    periodStart: date = Field(..., description="Period start date", json_schema_extra={"label": "Periodenbeginn"})

    # Aggregated values
    totalCostCHF: float = Field(default=0.0, description="Total cost in CHF", json_schema_extra={"label": "Gesamtkosten (CHF)"})
    transactionCount: int = Field(default=0, description="Number of transactions", json_schema_extra={"label": "Anzahl Transaktionen"})

    # Breakdown by provider
    costByProvider: Dict[str, float] = Field(
        default_factory=dict,
        description="Cost breakdown by provider (e.g., {'anthropic': 12.50, 'openai': 8.30})",
        json_schema_extra={"label": "Kosten nach Anbieter"},
    )

    # Breakdown by feature
    costByFeature: Dict[str, float] = Field(
        default_factory=dict,
        description="Cost breakdown by feature (e.g., {'automation': 5.80, 'workspace': 3.20})",
        json_schema_extra={"label": "Kosten nach Feature"},
    )


# ============================================================================
# Response Models for API
# ============================================================================

class BillingBalanceResponse(BaseModel):
    """Response model for balance endpoint."""
    mandateId: str
    mandateName: str
    balance: float
    currency: str = "CHF"
    warningThreshold: float
    isWarning: bool


class BillingStatisticsChartData(BaseModel):
    """Chart data point for statistics."""
    label: str
    totalCost: float
    byProvider: Dict[str, float]


class BillingStatisticsResponse(BaseModel):
    """Response model for statistics endpoint."""
    mandateId: str
    period: PeriodTypeEnum
    year: int
    month: Optional[int] = None
    currency: str = "CHF"
    data: List[BillingStatisticsChartData]
    totals: Dict[str, Any]


class BillingCheckResult(BaseModel):
    """Result of a billing balance check (budget + subscription gate)."""
    allowed: bool
    reason: Optional[str] = None
    currentBalance: Optional[float] = None
    requiredAmount: Optional[float] = None
    upgradeRequired: Optional[bool] = None
    subscriptionUiPath: Optional[str] = None
    userAction: Optional[str] = None

