# 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.alert_application_config_output import AlertApplicationConfigOutput
from mixpeek.models.bucket_schema_output import BucketSchemaOutput
from mixpeek.models.cluster_application_config import ClusterApplicationConfig
from mixpeek.models.shared_collection_features_extractors_models_feature_extractor_config_output import SharedCollectionFeaturesExtractorsModelsFeatureExtractorConfigOutput
from mixpeek.models.single_lineage_entry import SingleLineageEntry
from mixpeek.models.source_config_output import SourceConfigOutput
from mixpeek.models.taxonomy_application_config_output import TaxonomyApplicationConfigOutput
from typing import Optional, Set
from typing_extensions import Self

class CollectionResponse(BaseModel):
    """
    Response model for collection endpoints.
    """ # noqa: E501
    collection_id: Optional[StrictStr] = Field(default=None, description="NOT REQUIRED (auto-generated). Unique identifier for this collection. Used for: API paths, document queries, pipeline references. Format: 'col_' prefix + 10 random alphanumeric characters. Stable after creation - use for all collection references.")
    collection_name: Annotated[str, Field(min_length=3, strict=True, max_length=100)] = Field(description="REQUIRED. Human-readable name for the collection. Must be unique within the namespace. Used for: Display, lookups (can query by name or ID), organization. Format: Alphanumeric with underscores/hyphens, 3-100 characters. Examples: 'product_embeddings', 'video_frames', 'customer_documents'.")
    description: Optional[StrictStr] = Field(default=None, description="NOT REQUIRED. Human-readable description of the collection's purpose. Use for: Documentation, team communication, UI display. Common pattern: Describe what the collection contains and what processing is applied.")
    input_schema: BucketSchemaOutput = Field(description="REQUIRED (auto-computed from source). Input schema defining fields available to the feature extractor. Source: bucket.bucket_schema (if source.type='bucket') OR upstream_collection.output_schema (if source.type='collection'). Determines: Which fields can be used in input_mappings and field_passthrough. This is the 'left side' of the transformation - what data goes IN. Format: BucketSchema with properties dict. Use for: Validating input_mappings, configuring field_passthrough.")
    output_schema: BucketSchemaOutput = Field(description="REQUIRED (auto-computed at creation). Output schema defining fields in final documents. Computed as: field_passthrough fields + extractor output fields (deterministic). Known IMMEDIATELY when collection is created - no waiting for documents! This is the 'right side' of the transformation - what data comes OUT. Use for: Understanding document structure, building queries, schema validation. Example: {title (passthrough), embedding (extractor output)} = output_schema.")
    feature_extractor: SharedCollectionFeaturesExtractorsModelsFeatureExtractorConfigOutput = Field(description="REQUIRED. Single feature extractor configuration for this collection. Defines: extractor name/version, input_mappings, field_passthrough, parameters. Task 9 change: ONE extractor per collection (previously supported multiple). For multiple extractors: Create multiple collections and use collection-to-collection pipelines. Use field_passthrough to include additional source fields beyond extractor outputs.")
    source: SourceConfigOutput = Field(description="REQUIRED. Source configuration defining where data comes from. Type 'bucket': Process objects from one or more buckets (tier 1). Type 'collection': Process documents from upstream collection(s) (tier 2+). For multi-bucket sources, all buckets must have compatible schemas. For multi-collection sources, all collections must have compatible schemas. Determines input_schema and enables decomposition trees.")
    source_bucket_schemas: Optional[Dict[str, BucketSchemaOutput]] = Field(default=None, description="NOT REQUIRED (auto-computed). Snapshot of bucket schemas at collection creation. Only populated for multi-bucket collections (source.type='bucket' with multiple bucket_ids). Key: bucket_id, Value: BucketSchema at time of collection creation. Used for: Schema compatibility validation, document lineage, debugging. Schema snapshot is immutable - bucket schema changes after collection creation do not affect this. Single-bucket collections may omit this field (schema in input_schema is sufficient).")
    source_lineage: Optional[List[SingleLineageEntry]] = Field(default=None, description="NOT REQUIRED (auto-computed). Lineage chain showing complete processing history. Each entry contains: source_config, feature_extractor, output_schema for one tier. Length indicates processing depth (1 = tier 1, 2 = tier 2, etc.). Use for: Understanding multi-tier pipelines, visualizing decomposition trees.")
    vector_indexes: Optional[List[Any]] = Field(default=None, description="NOT REQUIRED (auto-computed from extractor). Vector indexes for semantic search. Populated from feature_extractor.required_vector_indexes. Defines: Which embeddings are indexed, dimensions, distance metrics. Use for: Understanding search capabilities, debugging vector queries.")
    payload_indexes: Optional[List[Any]] = Field(default=None, description="NOT REQUIRED (auto-computed from extractor + namespace). Payload indexes for filtering. Enables efficient filtering on metadata fields, timestamps, IDs. Populated from: extractor requirements + namespace defaults. Use for: Understanding which fields support fast filtering.")
    enabled: Optional[StrictBool] = Field(default=True, description="NOT REQUIRED (defaults to True). Whether the collection accepts new documents. False: Collection exists but won't process new objects. True: Active and processing. Use for: Temporarily disabling collections without deletion.")
    metadata: Optional[Dict[str, Any]] = Field(default=None, description="NOT REQUIRED. Additional user-defined metadata for the collection. Arbitrary key-value pairs for custom organization, tracking, configuration. Not used by the platform - purely for user purposes. Common uses: team ownership, project tags, deployment environment.")
    created_at: Optional[datetime] = Field(default=None, description="Timestamp when the collection was created. Automatically set by the system when the collection is first saved to the database.")
    updated_at: Optional[datetime] = Field(default=None, description="Timestamp when the collection was last updated. Automatically updated by the system whenever the collection is modified.")
    document_count: Optional[StrictInt] = Field(default=None, description="Number of documents in the collection")
    schema_version: Optional[StrictInt] = Field(default=1, description="Version number for the output_schema. Increments automatically when schema is updated via document sampling. Used to track schema evolution and trigger downstream collection schema updates.")
    last_schema_sync: Optional[datetime] = Field(default=None, description="Timestamp of last automatic schema sync from document sampling. Used to debounce schema updates (prevents thrashing).")
    schema_sync_enabled: Optional[StrictBool] = Field(default=True, description="Whether automatic schema discovery and sync is enabled for this collection. When True, schema is periodically updated by sampling documents. When False, schema remains fixed at creation time.")
    taxonomy_applications: Optional[List[TaxonomyApplicationConfigOutput]] = Field(default=None, description="NOT REQUIRED. List of taxonomies to apply to documents in this collection. Each entry specifies: taxonomy_id, optional target_collection_id, optional filters. Enrichments are materialized (persisted to documents) during ingestion. Empty/null if no taxonomies attached. Use for: Categorization, hierarchical classification.")
    cluster_applications: Optional[List[ClusterApplicationConfig]] = Field(default=None, description="NOT REQUIRED. List of clusters to automatically execute when batch processing completes. Each entry specifies: cluster_id, auto_execute_on_batch, min_document_threshold, cooldown_seconds. Clusters enrich source documents with cluster assignments (cluster_id, cluster_label, etc.). Empty/null if no clusters attached. Use for: Segmentation, grouping, pattern discovery.")
    alert_applications: Optional[List[AlertApplicationConfigOutput]] = Field(default=None, description="NOT REQUIRED. List of alerts to automatically execute when documents are ingested. Each entry specifies: alert_id, execution_mode, input_mappings, execution_phase, priority. Alerts run retrievers on ingested documents and send notifications when matches are found. Empty/null if no alerts attached. Use for: Content monitoring, safety detection, compliance alerts.")
    taxonomy_count: Optional[StrictInt] = Field(default=None, description="Number of taxonomies connected to this collection")
    retriever_count: Optional[StrictInt] = Field(default=None, description="Number of retrievers connected to this collection")
    __properties: ClassVar[List[str]] = ["collection_id", "collection_name", "description", "input_schema", "output_schema", "feature_extractor", "source", "source_bucket_schemas", "source_lineage", "vector_indexes", "payload_indexes", "enabled", "metadata", "created_at", "updated_at", "document_count", "schema_version", "last_schema_sync", "schema_sync_enabled", "taxonomy_applications", "cluster_applications", "alert_applications", "taxonomy_count", "retriever_count"]

    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 CollectionResponse 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 input_schema
        if self.input_schema:
            _dict['input_schema'] = self.input_schema.to_dict()
        # override the default output from pydantic by calling `to_dict()` of output_schema
        if self.output_schema:
            _dict['output_schema'] = self.output_schema.to_dict()
        # override the default output from pydantic by calling `to_dict()` of feature_extractor
        if self.feature_extractor:
            _dict['feature_extractor'] = self.feature_extractor.to_dict()
        # override the default output from pydantic by calling `to_dict()` of source
        if self.source:
            _dict['source'] = self.source.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each value in source_bucket_schemas (dict)
        _field_dict = {}
        if self.source_bucket_schemas:
            for _key_source_bucket_schemas in self.source_bucket_schemas:
                if self.source_bucket_schemas[_key_source_bucket_schemas]:
                    _field_dict[_key_source_bucket_schemas] = self.source_bucket_schemas[_key_source_bucket_schemas].to_dict()
            _dict['source_bucket_schemas'] = _field_dict
        # override the default output from pydantic by calling `to_dict()` of each item in source_lineage (list)
        _items = []
        if self.source_lineage:
            for _item_source_lineage in self.source_lineage:
                if _item_source_lineage:
                    _items.append(_item_source_lineage.to_dict())
            _dict['source_lineage'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in taxonomy_applications (list)
        _items = []
        if self.taxonomy_applications:
            for _item_taxonomy_applications in self.taxonomy_applications:
                if _item_taxonomy_applications:
                    _items.append(_item_taxonomy_applications.to_dict())
            _dict['taxonomy_applications'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in cluster_applications (list)
        _items = []
        if self.cluster_applications:
            for _item_cluster_applications in self.cluster_applications:
                if _item_cluster_applications:
                    _items.append(_item_cluster_applications.to_dict())
            _dict['cluster_applications'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in alert_applications (list)
        _items = []
        if self.alert_applications:
            for _item_alert_applications in self.alert_applications:
                if _item_alert_applications:
                    _items.append(_item_alert_applications.to_dict())
            _dict['alert_applications'] = _items
        return _dict

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

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

        _obj = cls.model_validate({
            "collection_id": obj.get("collection_id"),
            "collection_name": obj.get("collection_name"),
            "description": obj.get("description"),
            "input_schema": BucketSchemaOutput.from_dict(obj["input_schema"]) if obj.get("input_schema") is not None else None,
            "output_schema": BucketSchemaOutput.from_dict(obj["output_schema"]) if obj.get("output_schema") is not None else None,
            "feature_extractor": SharedCollectionFeaturesExtractorsModelsFeatureExtractorConfigOutput.from_dict(obj["feature_extractor"]) if obj.get("feature_extractor") is not None else None,
            "source": SourceConfigOutput.from_dict(obj["source"]) if obj.get("source") is not None else None,
            "source_bucket_schemas": dict(
                (_k, BucketSchemaOutput.from_dict(_v))
                for _k, _v in obj["source_bucket_schemas"].items()
            )
            if obj.get("source_bucket_schemas") is not None
            else None,
            "source_lineage": [SingleLineageEntry.from_dict(_item) for _item in obj["source_lineage"]] if obj.get("source_lineage") is not None else None,
            "vector_indexes": obj.get("vector_indexes"),
            "payload_indexes": obj.get("payload_indexes"),
            "enabled": obj.get("enabled") if obj.get("enabled") is not None else True,
            "metadata": obj.get("metadata"),
            "created_at": obj.get("created_at"),
            "updated_at": obj.get("updated_at"),
            "document_count": obj.get("document_count"),
            "schema_version": obj.get("schema_version") if obj.get("schema_version") is not None else 1,
            "last_schema_sync": obj.get("last_schema_sync"),
            "schema_sync_enabled": obj.get("schema_sync_enabled") if obj.get("schema_sync_enabled") is not None else True,
            "taxonomy_applications": [TaxonomyApplicationConfigOutput.from_dict(_item) for _item in obj["taxonomy_applications"]] if obj.get("taxonomy_applications") is not None else None,
            "cluster_applications": [ClusterApplicationConfig.from_dict(_item) for _item in obj["cluster_applications"]] if obj.get("cluster_applications") is not None else None,
            "alert_applications": [AlertApplicationConfigOutput.from_dict(_item) for _item in obj["alert_applications"]] if obj.get("alert_applications") is not None else None,
            "taxonomy_count": obj.get("taxonomy_count"),
            "retriever_count": obj.get("retriever_count")
        })
        return _obj


