# 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 pydantic import BaseModel, ConfigDict, Field, StrictStr
from typing import Any, ClassVar, Dict, List, Optional, Union
from typing_extensions import Annotated
from mixpeek.models.enrichment_field import EnrichmentField
from mixpeek.models.logical_operator import LogicalOperator
from typing import Optional, Set
from typing_extensions import Self

class StageParamsTaxonomyEnrich(BaseModel):
    """
    Configuration for enriching documents with taxonomy assignments.  **Stage Category**: APPLY (1-1 or 1-N depending on configuration)  **Transformation**:     - 1-1 mode (top_k=1): N documents → N documents (same count, expanded schema)     - 1-N mode (top_k>1): N documents → N*M documents (outer join/tagging)  **Purpose**: Applies each document to a taxonomy search, matching against predefined taxonomy nodes using vector similarity. Can operate as 1-1 enrichment (single best match) or 1-N expansion (multiple matching tags).  **When to Use**:     - After FILTER/SORT to classify and tag retrieved documents     - For automatic content categorization (topics, genres, entities)     - When you have labeled reference data (people, products, categories)     - For face recognition (matching faces against enrolled identities)     - To apply hierarchical categorization (parent/child relationships)     - For entity linking (matching content to knowledge base entities)     - **1-1 mode** (top_k=1): Single best match enrichment     - **1-N mode** (top_k>1): Multi-tag expansion (document multiplication)  **When NOT to Use**:     - For initial document retrieval from collections (use FILTER: hybrid_search)     - For removing documents (use FILTER stages)     - For reordering results (use SORT stages)     - For general field-based JOINs (use document_enrich instead)     - When you don't have a predefined taxonomy collection  **Operational Behavior**:     - Applies each input document to taxonomy vector search     - Performs vector similarity search against taxonomy collection (Qdrant)     - Document count: N in → N out (top_k=1) or N*M out (top_k>1)     - Expands or maintains schema depending on mode     - Moderate performance (vector similarity searches per document)     - Supports conditional enrichment (via `when` parameter for cost savings)  **Common Pipeline Position**: FILTER → SORT → APPLY (this stage)  **Conditional Enrichment**: Supports `when` parameter to only enrich documents matching specific criteria. Critical for:     - Cost savings (vector searches are compute-intensive)     - Selective enrichment based on document properties     - Applying different taxonomies to different document types  Requirements:     - taxonomy_id: REQUIRED - ID of the taxonomy to use for enrichment     - fields: OPTIONAL, which taxonomy fields to merge into documents     - top_k: OPTIONAL, max taxonomy matches per document (default 3)     - min_score: OPTIONAL, minimum similarity threshold (default 0.0)     - when: OPTIONAL, condition for selective enrichment  Use Cases:     - Face recognition: Match detected faces to employee directory     - Content classification: Tag articles with topic categories     - Product categorization: Assign products to taxonomy of categories     - Entity linking: Link mentions to knowledge base entities     - Brand detection: Identify brand logos in images  Examples:     Basic taxonomy enrichment:         ```json         {             \"taxonomy_id\": \"tax_abc123\",             \"top_k\": 3         }         ```      Conditional enrichment (only enrich if category=product):         ```json         {             \"taxonomy_id\": \"tax_product_classifier\",             \"top_k\": 3,             \"when\": {                 \"AND\": [                     {\"field\": \"metadata.category\", \"operator\": \"eq\", \"value\": \"product\"},                     {\"field\": \"metadata.has_image\", \"operator\": \"eq\", \"value\": true}                 ]             }         }         ```
    """ # noqa: E501
    taxonomy_id: Optional[StrictStr] = Field(default='{{TAXONOMY_ID}}', description="ID of the taxonomy to use for enrichment. The taxonomy's configured input_mappings determine which vector field from source documents to use for similarity matching. NOTE: You must replace the default placeholder with your actual taxonomy ID.")
    fields: Optional[List[EnrichmentField]] = Field(default=None, description="Fields from the taxonomy node to merge into the document.")
    top_k: Optional[Annotated[int, Field(le=50, strict=True, ge=1)]] = Field(default=3, description="Maximum taxonomy assignments to attach per document.")
    min_score: Optional[Union[Annotated[float, Field(le=1.0, strict=True, ge=0.0)], Annotated[int, Field(le=1, strict=True, ge=0)]]] = Field(default=0.0, description="Minimum similarity score required to keep an assignment.")
    when: Optional[LogicalOperator] = Field(default=None, description="OPTIONAL. Conditional filter that documents must satisfy to be enriched. Uses LogicalOperator (AND/OR/NOT) for complex boolean logic, or simple field/operator/value for single conditions. Documents NOT matching this condition will SKIP enrichment (pass-through unchanged). Useful for cost savings (only enrich relevant documents) and conditional processing. When NOT specified, ALL documents are enriched unconditionally.   Simple condition example: {\"field\": \"metadata.category\", \"operator\": \"eq\", \"value\": \"product\"} Boolean AND example: {\"AND\": [{\"field\": \"x\", \"operator\": \"eq\", \"value\": \"y\"}, ...]} Boolean OR example: {\"OR\": [{\"field\": \"x\", \"operator\": \"eq\", \"value\": \"y\"}, ...]} ")
    __properties: ClassVar[List[str]] = ["taxonomy_id", "fields", "top_k", "min_score", "when"]

    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 StageParamsTaxonomyEnrich 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 each item in fields (list)
        _items = []
        if self.fields:
            for _item_fields in self.fields:
                if _item_fields:
                    _items.append(_item_fields.to_dict())
            _dict['fields'] = _items
        # override the default output from pydantic by calling `to_dict()` of when
        if self.when:
            _dict['when'] = self.when.to_dict()
        return _dict

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

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

        _obj = cls.model_validate({
            "taxonomy_id": obj.get("taxonomy_id") if obj.get("taxonomy_id") is not None else '{{TAXONOMY_ID}}',
            "fields": [EnrichmentField.from_dict(_item) for _item in obj["fields"]] if obj.get("fields") is not None else None,
            "top_k": obj.get("top_k") if obj.get("top_k") is not None else 3,
            "min_score": obj.get("min_score") if obj.get("min_score") is not None else 0.0,
            "when": LogicalOperator.from_dict(obj["when"]) if obj.get("when") is not None else None
        })
        return _obj


