# coding: utf-8

"""
    Mixpeek API

    This is the Mixpeek API, providing access to various endpoints for data processing and retrieval.

    The version of the OpenAPI document: 1.3.0
    Contact: info@mixpeek.com
    Generated by OpenAPI Generator (https://openapi-generator.tech)

    Do not edit the class manually.
"""  # noqa: E501


from __future__ import annotations
import pprint
import re  # noqa: F401
import json

from datetime import datetime
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr
from typing import Any, ClassVar, Dict, List, Optional
from typing_extensions import Annotated
from mixpeek.models.account_tier import AccountTier
from mixpeek.models.audit_settings import AuditSettings
from mixpeek.models.base_rate_limits import BaseRateLimits
from mixpeek.models.organization_infrastructure import OrganizationInfrastructure
from typing import Optional, Set
from typing_extensions import Self

class OrganizationModel(BaseModel):
    """
    Organization document representing a tenant in the multi-tenant system.  Multi-Tenancy Architecture:     Organizations are the root tenant in Mixpeek's multi-tenant architecture.     Each organization has dual identifiers optimized for different purposes:      - internal_id: Backend tenant isolation (database queries, scoping)     - organization_id: Frontend/user-facing identifier (APIs, logs, support)  ID Usage Patterns:     Database Queries:         ✅ service = CollectionService(internal_id=org.internal_id)         ❌ service = CollectionService(internal_id=org.organization_id)  # Wrong!      Error Messages:         ✅ raise NotFoundError(details={\"organization_id\": org.organization_id})         ❌ raise NotFoundError(details={\"internal_id\": org.internal_id})  # Don't expose!      Logging:         ✅ logger.info(f\"Action for org {org.organization_id}\", extra={\"internal_id\": org.internal_id})         ❌ logger.info(f\"Action for org {org.internal_id}\")  # Not user-friendly!  Security Model:     - internal_id is HIGH-ENTROPY (24 chars) and treated as a secret     - organization_id is LOWER-ENTROPY (15 chars) and safe to expose     - Never expose internal_id in API responses or user-facing messages
    """ # noqa: E501
    internal_id: Optional[StrictStr] = Field(default=None, description="Internal organization identifier for multi-tenancy. High-entropy secret (24 chars) used exclusively for database queries and tenant isolation. This ID is immutable and never exposed in user-facing contexts. Format: int_xxxxxxxxxxxxxxxxxxxxx. USAGE: Database scoping, service initialization, provider configuration.")
    organization_id: Optional[StrictStr] = Field(default=None, description="Public organization identifier exposed in APIs and user-facing contexts. Lower-entropy ID (15 chars) safe for logs, error messages, and API responses. This ID can be changed for rebranding without affecting backend operations. Format: org_xxxxxxxxxxxxx. USAGE: API responses, error messages, logs, support tickets, analytics.")
    organization_name: StrictStr = Field(description="Display name of the organization.")
    logo_url: Optional[StrictStr] = Field(default=None, description="URL to organization's logo image. Automatically fetched from Google's favicon service based on user's email domain during org creation. Can be overridden with custom URL. Format: https://www.google.com/s2/favicons?domain=... or custom URL.")
    account_type: Optional[AccountTier] = Field(default=None, description="Billing tier determining available features and limits.")
    credit_count: Optional[StrictInt] = Field(default=0, description="DEPRECATED: Legacy credit balance. Use current_month_usage instead.")
    free_tier_usage_limit: Optional[StrictInt] = Field(default=1000, description="Maximum usage allowed before payment method required. Once current_month_usage exceeds this AND auto_billing is disabled, API access is blocked until payment method is added.")
    metadata: Optional[Dict[str, Any]] = Field(default=None, description="Custom metadata applied to the organization.")
    billing_email: Optional[StrictStr] = Field(default=None, description="Email address for invoices and billing notifications.")
    stripe_customer_id: Optional[StrictStr] = Field(default=None, description="Stripe Customer ID for usage-based billing. Created when organization sets up payment method. Format: cus_xxxxxxxxxxxxx")
    default_payment_method_id: Optional[StrictStr] = Field(default=None, description="Default Stripe PaymentMethod ID for automatic monthly billing. Set when organization attaches a payment method. Format: pm_xxxxxxxxxxxxx")
    auto_billing_enabled: Optional[StrictBool] = Field(default=False, description="Whether automatic monthly billing is enabled. When True, organization is charged automatically at end of month for usage. When False, organization uses manual credit purchases (legacy mode).")
    billing_cycle_start: Optional[Annotated[int, Field(le=31, strict=True, ge=1)]] = Field(default=1, description="Day of month when billing cycle starts (1-31). Invoices are generated on this day each month. If day doesn't exist in month (e.g., 31 in Feb), uses last day of month.")
    current_month_usage: Optional[StrictInt] = Field(default=0, description="Credits consumed in current billing cycle. Reset to 0 after invoice generation. Used for real-time usage display in dashboard.")
    last_invoice_date: Optional[datetime] = Field(default=None, description="UTC timestamp of last invoice generation. Used to determine billing period and prevent duplicate invoices.")
    billing_period_start: Optional[datetime] = Field(default=None, description="UTC timestamp when current billing period started. Set when invoice is generated or billing enabled.")
    monthly_spending_budget: Optional[StrictInt] = Field(default=None, description="Soft spending limit in USD cents for the current billing cycle. When set, triggers alerts at specified thresholds but doesn't block API access. Example: 10000 = $100 budget. None = no budget limit (unlimited spending allowed).")
    spending_alert_thresholds: Optional[List[StrictInt]] = Field(default=None, description="Percentage thresholds for spending alerts (0-100). When current spending reaches each threshold, an alert is sent. Default: [50, 75, 90, 100] sends alerts at 50%, 75%, 90%, and 100% of budget. Only applies when monthly_spending_budget is set.")
    spending_alerts_enabled: Optional[StrictBool] = Field(default=True, description="Whether to send spending alerts when thresholds are crossed. When False, no alerts are sent even if thresholds are exceeded.")
    spending_alerts_sent: Optional[List[StrictInt]] = Field(default=None, description="Track which alert thresholds have been triggered in current billing cycle. Prevents duplicate alert notifications. Reset to empty list when invoice is generated. Example: [50, 75] means 50% and 75% alerts have been sent.")
    hard_spending_cap: Optional[StrictInt] = Field(default=None, description="Hard spending limit in USD cents for the current billing cycle. When reached, API access is blocked (similar to free tier limit). Example: 100000 = $1000 hard cap. None = no hard cap (only soft alerts apply). IMPORTANT: When enabled, operations are rejected once cap is reached.")
    hard_cap_enabled: Optional[StrictBool] = Field(default=False, description="Whether to enforce the hard spending cap. When True and hard_spending_cap is set, API access is blocked at cap. When False, hard_spending_cap is ignored (only soft alerts apply). Users must explicitly enable this for protection.")
    rate_limits: Optional[BaseRateLimits] = Field(default=None, description="Effective rate-limit configuration for the organization.")
    created_at: Optional[datetime] = Field(default=None, description="UTC timestamp when the organization was created.")
    updated_at: Optional[datetime] = Field(default=None, description="UTC timestamp of the most recent organization update.")
    users: Optional[List[Dict[str, Any]]] = Field(default=None, description="Deprecated nested user documents (maintained for backwards compatibility during migration).")
    infrastructure: Optional[OrganizationInfrastructure] = Field(default=None, description="Infrastructure configuration for dedicated resources. None for SHARED tier (FREE/PRO organizations using Mixpeek infrastructure). Configured for ENTERPRISE tier with dedicated Qdrant/Ray instances. Inherited by all namespaces unless overridden at namespace level.")
    max_dedicated_clusters: Optional[Annotated[int, Field(strict=True, ge=0)]] = Field(default=0, description="Maximum number of dedicated infrastructure clusters allowed for this organization. 0 for non-enterprise tiers (FREE, STARTER, PROFESSIONAL). Set based on enterprise tier package (e.g., 3, 5, 10, unlimited). Each cluster includes dedicated Anyscale/Ray compute + Qdrant database.")
    dedicated_cluster_ids: Optional[List[StrictStr]] = Field(default=None, description="List of dedicated infrastructure cluster IDs owned by this organization. Only applicable for Enterprise tier. Format: iclstr_xxxxxxxxxxxxx")
    secrets: Optional[Dict[str, StrictStr]] = Field(default=None, description="Encrypted secrets vault for API integrations and external service credentials. Keys are secret names (e.g., 'stripe_api_key', 'github_token'), values are encrypted strings stored using Fernet encryption. Used by api_call retriever stage for secure credential storage. Secrets are encrypted on write and decrypted on read using ENCRYPTION_KEY. NEVER expose decrypted values in API responses or logs. Note: Values are stored as encrypted strings (bytes), not EncryptedStr type.")
    audit_settings: Optional[AuditSettings] = Field(default=None, description="Audit trail configuration for the organization. Controls whether read operations are logged to the audit trail. By default, only write operations (create, update, delete) are audited.")
    __properties: ClassVar[List[str]] = ["internal_id", "organization_id", "organization_name", "logo_url", "account_type", "credit_count", "free_tier_usage_limit", "metadata", "billing_email", "stripe_customer_id", "default_payment_method_id", "auto_billing_enabled", "billing_cycle_start", "current_month_usage", "last_invoice_date", "billing_period_start", "monthly_spending_budget", "spending_alert_thresholds", "spending_alerts_enabled", "spending_alerts_sent", "hard_spending_cap", "hard_cap_enabled", "rate_limits", "created_at", "updated_at", "users", "infrastructure", "max_dedicated_clusters", "dedicated_cluster_ids", "secrets", "audit_settings"]

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


    def to_str(self) -> str:
        """Returns the string representation of the model using alias"""
        return pprint.pformat(self.model_dump(by_alias=True))

    def to_json(self) -> str:
        """Returns the JSON representation of the model using alias"""
        # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
        return json.dumps(self.to_dict())

    @classmethod
    def from_json(cls, json_str: str) -> Optional[Self]:
        """Create an instance of OrganizationModel from a JSON string"""
        return cls.from_dict(json.loads(json_str))

    def to_dict(self) -> Dict[str, Any]:
        """Return the dictionary representation of the model using alias.

        This has the following differences from calling pydantic's
        `self.model_dump(by_alias=True)`:

        * `None` is only added to the output dict for nullable fields that
          were set at model initialization. Other fields with value `None`
          are ignored.
        """
        excluded_fields: Set[str] = set([
        ])

        _dict = self.model_dump(
            by_alias=True,
            exclude=excluded_fields,
            exclude_none=True,
        )
        # override the default output from pydantic by calling `to_dict()` of rate_limits
        if self.rate_limits:
            _dict['rate_limits'] = self.rate_limits.to_dict()
        # override the default output from pydantic by calling `to_dict()` of infrastructure
        if self.infrastructure:
            _dict['infrastructure'] = self.infrastructure.to_dict()
        # override the default output from pydantic by calling `to_dict()` of audit_settings
        if self.audit_settings:
            _dict['audit_settings'] = self.audit_settings.to_dict()
        return _dict

    @classmethod
    def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
        """Create an instance of OrganizationModel from a dict"""
        if obj is None:
            return None

        if not isinstance(obj, dict):
            return cls.model_validate(obj)

        _obj = cls.model_validate({
            "internal_id": obj.get("internal_id"),
            "organization_id": obj.get("organization_id"),
            "organization_name": obj.get("organization_name"),
            "logo_url": obj.get("logo_url"),
            "account_type": obj.get("account_type"),
            "credit_count": obj.get("credit_count") if obj.get("credit_count") is not None else 0,
            "free_tier_usage_limit": obj.get("free_tier_usage_limit") if obj.get("free_tier_usage_limit") is not None else 1000,
            "metadata": obj.get("metadata"),
            "billing_email": obj.get("billing_email"),
            "stripe_customer_id": obj.get("stripe_customer_id"),
            "default_payment_method_id": obj.get("default_payment_method_id"),
            "auto_billing_enabled": obj.get("auto_billing_enabled") if obj.get("auto_billing_enabled") is not None else False,
            "billing_cycle_start": obj.get("billing_cycle_start") if obj.get("billing_cycle_start") is not None else 1,
            "current_month_usage": obj.get("current_month_usage") if obj.get("current_month_usage") is not None else 0,
            "last_invoice_date": obj.get("last_invoice_date"),
            "billing_period_start": obj.get("billing_period_start"),
            "monthly_spending_budget": obj.get("monthly_spending_budget"),
            "spending_alert_thresholds": obj.get("spending_alert_thresholds"),
            "spending_alerts_enabled": obj.get("spending_alerts_enabled") if obj.get("spending_alerts_enabled") is not None else True,
            "spending_alerts_sent": obj.get("spending_alerts_sent"),
            "hard_spending_cap": obj.get("hard_spending_cap"),
            "hard_cap_enabled": obj.get("hard_cap_enabled") if obj.get("hard_cap_enabled") is not None else False,
            "rate_limits": BaseRateLimits.from_dict(obj["rate_limits"]) if obj.get("rate_limits") is not None else None,
            "created_at": obj.get("created_at"),
            "updated_at": obj.get("updated_at"),
            "users": obj.get("users"),
            "infrastructure": OrganizationInfrastructure.from_dict(obj["infrastructure"]) if obj.get("infrastructure") is not None else None,
            "max_dedicated_clusters": obj.get("max_dedicated_clusters") if obj.get("max_dedicated_clusters") is not None else 0,
            "dedicated_cluster_ids": obj.get("dedicated_cluster_ids"),
            "secrets": obj.get("secrets"),
            "audit_settings": AuditSettings.from_dict(obj["audit_settings"]) if obj.get("audit_settings") is not None else None
        })
        return _obj


