"""Organization and billing domain models for CleverAgents.

Based on Phase 0 discovery stubs with additional validation rules from ADR-004
(Pydantic Validation).
"""

from __future__ import annotations

from datetime import datetime
from decimal import Decimal
from enum import StrEnum

from pydantic import BaseModel, ConfigDict, Field

from ..orguserconfig.org_user_config import OrgUserConfig
from ..planconfig.plan_config import PlanConfig
from .enums import ModelProvider

__all__ = [
    "CloudBillingFields",
    "CreditType",
    "CreditsTransaction",
    "CreditsTransactionType",
    "Invite",
    "Org",
    "OrgRole",
    "OrgUser",
    "User",
]


class OrgRole(BaseModel):
    """Organization role metadata."""

    id: str = Field(..., description="Role identifier")
    is_default: bool = Field(..., alias="isDefault")
    label: str = Field(..., min_length=1)
    description: str = Field(..., min_length=1)

    model_config = ConfigDict(
        str_strip_whitespace=True,
        validate_assignment=True,
        populate_by_name=True,
    )


class CloudBillingFields(BaseModel):
    """Billing configuration for a CleverAgents organization."""

    credits_balance: Decimal = Field(..., alias="creditsBalance")
    monthly_grant: Decimal = Field(..., alias="monthlyGrant")
    auto_rebuy_enabled: bool = Field(..., alias="autoRebuyEnabled")
    auto_rebuy_min_threshold: Decimal = Field(..., alias="autoRebuyMinThreshold")
    auto_rebuy_to_balance: Decimal = Field(..., alias="autoRebuyToBalance")
    notify_threshold: Decimal = Field(..., alias="notifyThreshold")
    max_threshold_per_month: Decimal = Field(..., alias="maxThresholdPerMonth")
    billing_cycle_started_at: datetime = Field(..., alias="billingCycleStartedAt")
    changed_billing_mode: bool = Field(..., alias="changedBillingMode")
    trial_paid: bool = Field(..., alias="trialPaid")
    stripe_subscription_id: str | None = Field(
        default=None, alias="stripeSubscriptionId"
    )
    subscription_status: str | None = Field(default=None, alias="subscriptionStatus")
    subscription_paused_at: datetime | None = Field(
        default=None, alias="subscriptionPausedAt"
    )
    stripe_payment_method: str | None = Field(default=None, alias="stripePaymentMethod")
    subscription_action_required: bool = Field(..., alias="subscriptionActionRequired")
    subscription_action_required_invoice_url: str | None = Field(
        default=None, alias="subscriptionActionRequiredInvoiceUrl"
    )

    model_config = ConfigDict(
        str_strip_whitespace=True,
        validate_assignment=True,
        arbitrary_types_allowed=False,
        populate_by_name=True,
    )


class Org(BaseModel):
    """Organization profile."""

    id: str = Field(..., description="Organization identifier")
    name: str = Field(..., min_length=1)
    is_trial: bool = Field(..., alias="isTrial")
    auto_add_domain_users: bool = Field(..., alias="autoAddDomainUsers")
    integrated_models_mode: bool | None = Field(
        default=None, alias="integratedModelsMode"
    )
    cloud_billing_fields: CloudBillingFields | None = Field(
        default=None, alias="cloudBillingFields"
    )

    model_config = ConfigDict(
        str_strip_whitespace=True,
        validate_assignment=True,
        populate_by_name=True,
    )


class User(BaseModel):
    """User profile within an organization."""

    id: str = Field(...)
    name: str = Field(..., min_length=1)
    email: str = Field(..., min_length=3)
    is_trial: bool = Field(..., alias="isTrial")
    num_non_draft_plans: int = Field(..., alias="numNonDraftPlans", ge=0)
    default_plan_config: PlanConfig | None = Field(
        default=None, alias="defaultPlanConfig"
    )

    model_config = ConfigDict(
        str_strip_whitespace=True,
        validate_assignment=True,
        populate_by_name=True,
    )


class OrgUser(BaseModel):
    """Association between a user and an organization."""

    org_id: str = Field(..., alias="orgId")
    user_id: str = Field(..., alias="userId")
    org_role_id: str = Field(..., alias="orgRoleId")
    config: OrgUserConfig | None = Field(default=None)

    model_config = ConfigDict(
        str_strip_whitespace=True,
        validate_assignment=True,
        populate_by_name=True,
    )


class Invite(BaseModel):
    """Organization invitation record."""

    id: str = Field(...)
    org_id: str = Field(..., alias="orgId")
    email: str = Field(...)
    name: str = Field(...)
    org_role_id: str = Field(..., alias="orgRoleId")
    inviter_id: str = Field(..., alias="inviterId")
    invitee_id: str | None = Field(default=None, alias="inviteeId")
    accepted_at: datetime | None = Field(default=None, alias="acceptedAt")
    created_at: datetime = Field(..., alias="createdAt")

    model_config = ConfigDict(
        str_strip_whitespace=True,
        validate_assignment=True,
        populate_by_name=True,
    )


class CreditsTransactionType(StrEnum):
    """Type of credits transaction."""

    CREDIT = "CreditsTransactionTypeCredit"
    DEBIT = "CreditsTransactionTypeDebit"


class CreditType(StrEnum):
    """Categorization for credits changes."""

    TRIAL = "CreditTypeTrial"
    GRANT = "CreditTypeGrant"
    ADMIN_GRANT = "CreditTypeAdminGrant"
    PURCHASE = "CreditTypePurchase"
    SWITCH = "CreditTypeSwitch"


class CreditsTransaction(BaseModel):
    """Ledger entry for credits usage or replenishment."""

    id: str = Field(...)
    org_id: str = Field(..., alias="orgId")
    org_name: str = Field(..., alias="orgName")
    user_id: str | None = Field(default=None, alias="userId")
    user_email: str | None = Field(default=None, alias="userEmail")
    user_name: str | None = Field(default=None, alias="userName")
    transaction_type: CreditsTransactionType = Field(..., alias="transactionType")
    amount: Decimal = Field(...)
    start_balance: Decimal = Field(..., alias="startBalance")
    end_balance: Decimal = Field(..., alias="endBalance")
    credit_type: CreditType | None = Field(default=None, alias="creditType")
    credit_is_auto_rebuy: bool = Field(..., alias="creditIsAutoRebuy")
    credit_auto_rebuy_min_threshold: Decimal | None = Field(
        default=None, alias="creditAutoRebuyMinThreshold"
    )
    credit_auto_rebuy_to_balance: Decimal | None = Field(
        default=None, alias="creditAutoRebuyToBalance"
    )
    debit_input_tokens: int | None = Field(default=None, alias="debitInputTokens")
    debit_output_tokens: int | None = Field(default=None, alias="debitOutputTokens")
    debit_model_input_price_per_token: Decimal | None = Field(
        default=None, alias="debitModelInputPricePerToken"
    )
    debit_model_output_price_per_token: Decimal | None = Field(
        default=None, alias="debitModelOutputPricePerToken"
    )
    debit_base_amount: Decimal | None = Field(default=None, alias="debitBaseAmount")
    debit_surcharge: Decimal | None = Field(default=None, alias="debitSurcharge")
    debit_model_provider: ModelProvider | None = Field(
        default=None, alias="debitModelProvider"
    )
    debit_model_name: str | None = Field(default=None, alias="debitModelName")
    debit_model_pack_name: str | None = Field(default=None, alias="debitModelPackName")
    debit_model_role: str | None = Field(default=None, alias="debitModelRole")
    debit_purpose: str | None = Field(default=None, alias="debitPurpose")
    debit_plan_id: str | None = Field(default=None, alias="debitPlanId")
    debit_plan_name: str | None = Field(default=None, alias="debitPlanName")
    debit_id: str | None = Field(default=None, alias="debitId")
    debit_cache_discount: Decimal | None = Field(
        default=None, alias="debitCacheDiscount"
    )
    debit_session_id: str | None = Field(default=None, alias="debitSessionId")
    created_at: datetime = Field(..., alias="createdAt")

    model_config = ConfigDict(
        str_strip_whitespace=True,
        validate_assignment=True,
        arbitrary_types_allowed=False,
        populate_by_name=True,
        use_enum_values=True,
    )
