# 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, StrictStr
from typing import Any, ClassVar, Dict, List, Optional
from typing_extensions import Annotated
from mixpeek.models.provider_config import ProviderConfig
from mixpeek.models.storage_provider import StorageProvider
from mixpeek.models.task_status_enum import TaskStatusEnum
from typing import Optional, Set
from typing_extensions import Self

class StorageConnectionModel(BaseModel):
    """
    Canonical representation of an external storage provider connection.  Storage connections enable Mixpeek to access external cloud storage providers (Google Drive, S3, etc.) for automated file ingestion and synchronization. Each connection represents a configured integration with credentials, health monitoring, and usage tracking.  Lifecycle States:     - ACTIVE: Connection is healthy and ready for sync operations     - SUSPENDED: Temporarily disabled by user (credentials preserved)     - FAILED: Health checks failing (may need credential refresh)     - ARCHIVED: Permanently retired (cannot be reactivated)  Security:     - Sensitive credential fields are encrypted at rest using MongoDB       client-side field level encryption (CSFLE)     - Credentials never appear in API responses or logs     - Failed authentication attempts are logged in last_error     - Consecutive failures trigger automatic suspension  Use Cases:     - Connect to team Google Drive for document ingestion     - Sync files from customer S3 buckets     - Monitor and process uploaded media files     - Schedule periodic sync operations  Health Monitoring:     - Automatic health checks validate connectivity and credentials     - consecutive_failures tracks authentication/network issues     - Auto-disable after 5 consecutive failures to prevent lockout     - last_error stores diagnostic information for debugging
    """ # noqa: E501
    connection_id: Optional[StrictStr] = Field(default=None, description="Unique identifier for the storage connection. Auto-generated with 'conn_' prefix followed by secure random token. Format: conn_{15-character alphanumeric}. Used for API operations and audit trails.")
    internal_id: StrictStr = Field(description="REQUIRED. Organization internal identifier for multi-tenancy scoping. All connection operations are scoped to this organization. Format: int_{24-character secure token}.")
    provider_type: StorageProvider = Field(description="REQUIRED. Storage provider implementation to use. Determines which client adapter is loaded for sync operations. Supported: google_drive, s3, snowflake, sharepoint, tigris.")
    provider_config: ProviderConfig
    name: Annotated[str, Field(min_length=1, strict=True, max_length=100)] = Field(description="REQUIRED. Human-readable connection name for identification. Displayed in dashboards, sync logs, and API responses. Must be unique within the organization for clarity. Format: 1-100 characters, descriptive of the connection's purpose.")
    description: Optional[Annotated[str, Field(strict=True, max_length=500)]] = Field(default=None, description="NOT REQUIRED. Optional description explaining the connection's purpose and scope. Helpful for team collaboration and documentation. Format: Up to 500 characters.")
    status: Optional[TaskStatusEnum] = Field(default=None, description="Operational status of the connection. ACTIVE: Connection is healthy and ready for use in sync operations. SUSPENDED: Temporarily disabled by user, credentials preserved but sync paused. FAILED: Health checks failing, credentials may be invalid or expired. ARCHIVED: Permanently retired, cannot be reactivated. Status transitions automatically based on health checks and user actions.")
    is_active: Optional[StrictBool] = Field(default=True, description="Quick boolean flag for filtering active connections in queries. True when status is ACTIVE, False for SUSPENDED/FAILED/ARCHIVED. Maintained automatically when status changes. Use for efficient filtering: db.connections.find({'is_active': True})")
    last_used_at: Optional[datetime] = Field(default=None, description="NOT REQUIRED. UTC timestamp of the most recent successful sync operation. Updated automatically after each successful file sync/list operation. None if connection has never been used. Useful for identifying stale connections and usage analytics.")
    last_error: Optional[Annotated[str, Field(strict=True, max_length=1000)]] = Field(default=None, description="NOT REQUIRED. Most recent error message from failed health check or sync. Populated when authentication fails, network errors occur, or permissions denied. None when connection is healthy. Format: Error message truncated to 1000 characters. Used for diagnostics and troubleshooting.")
    consecutive_failures: Optional[Annotated[int, Field(strict=True, ge=0)]] = Field(default=0, description="Counter tracking consecutive failed health checks or sync attempts. Incremented on each failure, reset to 0 on success. Used to implement automatic connection suspension. Auto-suspend after 5 consecutive failures to prevent account lockout. Range: 0 to infinity (typically 0-10).")
    created_at: Optional[datetime] = Field(default=None, description="UTC timestamp when the connection was created. Auto-generated using shared.utilities.helpers.current_time(). Immutable after creation. Format: ISO 8601 datetime.")
    updated_at: Optional[datetime] = Field(default=None, description="UTC timestamp of the most recent update to the connection. Updated automatically on any field modification. Tracks configuration changes, status updates, and credential refreshes. Format: ISO 8601 datetime.")
    created_by_user_id: StrictStr = Field(description="REQUIRED. User identifier of the user who created this connection. Used for audit trails and permission checks. Format: usr_{15-character alphanumeric}. Immutable after creation.")
    metadata: Optional[Dict[str, Any]] = Field(default=None, description="Arbitrary key-value metadata provided by the user. Useful for tagging, categorization, and custom annotations. NOT REQUIRED - defaults to empty dictionary. Common uses: team tags, cost center codes, project identifiers.")
    __properties: ClassVar[List[str]] = ["connection_id", "internal_id", "provider_type", "provider_config", "name", "description", "status", "is_active", "last_used_at", "last_error", "consecutive_failures", "created_at", "updated_at", "created_by_user_id", "metadata"]

    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 StorageConnectionModel 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 provider_config
        if self.provider_config:
            _dict['provider_config'] = self.provider_config.to_dict()
        return _dict

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

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

        _obj = cls.model_validate({
            "connection_id": obj.get("connection_id"),
            "internal_id": obj.get("internal_id"),
            "provider_type": obj.get("provider_type"),
            "provider_config": ProviderConfig.from_dict(obj["provider_config"]) if obj.get("provider_config") is not None else None,
            "name": obj.get("name"),
            "description": obj.get("description"),
            "status": obj.get("status"),
            "is_active": obj.get("is_active") if obj.get("is_active") is not None else True,
            "last_used_at": obj.get("last_used_at"),
            "last_error": obj.get("last_error"),
            "consecutive_failures": obj.get("consecutive_failures") if obj.get("consecutive_failures") is not None else 0,
            "created_at": obj.get("created_at"),
            "updated_at": obj.get("updated_at"),
            "created_by_user_id": obj.get("created_by_user_id"),
            "metadata": obj.get("metadata")
        })
        return _obj


