# 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, field_validator
from typing import Any, ClassVar, Dict, List, Optional
from typing_extensions import Annotated
from mixpeek.models.enrichment_field import EnrichmentField
from mixpeek.models.input_mapping import InputMapping
from typing import Optional, Set
from typing_extensions import Self

class HierarchicalNodeInput(BaseModel):
    """
    A node in a hierarchical taxonomy representing one level in the tree structure.  Each node represents a collection containing documents at a specific hierarchy level. Nodes form parent-child relationships to create multi-level taxonomies with property inheritance. When a document matches a child node, it inherits all properties from parent nodes up to the root.  Use Cases:     - Define organizational hierarchies: employees → managers → executives     - Create product categorizations: products → electronics → phones → smartphones     - Build classification trees: industries → technology → software     - Implement face recognition hierarchies: people → employees → team members     - Enable property inheritance: child nodes get all parent properties  Hierarchy Behavior:     - Root nodes: parent_collection_id = None (top of hierarchy)     - Child nodes: parent_collection_id references parent node's collection_id     - Property inheritance: Children inherit all parent enrichment_fields     - Path construction: Creates path array from root to leaf     - Multi-level matching: Documents matched at deepest applicable level  Configuration:     - Per-node retrievers: Override taxonomy-level retriever for specific nodes     - Per-node enrichment: Override which fields to enrich at each level     - Per-node input mappings: Customize retriever inputs per hierarchy level     - Labels/summaries: Human-readable metadata for UI display  Related Models:     - HierarchicalTaxonomyConfig: Contains list of hierarchical nodes     - TaxonomyAssignment: Result of matching documents to nodes     - EnrichmentField: Specifies which fields to enrich from node  Requirements:     - collection_id: REQUIRED - must reference an existing collection     - parent_collection_id: REQUIRED for non-root nodes (None for root)     - All other fields: OPTIONAL with inheritance from taxonomy-level config
    """ # noqa: E501
    collection_id: Annotated[str, Field(strict=True)] = Field(description="REQUIRED. Collection ID representing this node in the hierarchy. Must reference an existing collection containing documents for this hierarchy level. Format: 'col_' prefix followed by alphanumeric/underscore characters. Used to: Match documents against this level, identify node in path, store enrichment data. Example: 'col_executives' for executive level, 'col_products_phones' for phones category.")
    parent_collection_id: Optional[Annotated[str, Field(strict=True)]] = Field(default=None, description="OPTIONAL. Collection ID of the parent node in the hierarchy. When None: This is a root node (top of hierarchy). When set: References parent node's collection_id, creating parent-child relationship. Format: Same as collection_id ('col_' prefix). Used to: Build hierarchy tree, determine inheritance order, construct path arrays. Example: 'col_managers' is parent of 'col_executives', 'col_products' is parent of 'col_electronics'. Validation: Must reference a valid collection_id from another node in same taxonomy.")
    label: Optional[StrictStr] = Field(default=None, description="OPTIONAL. Human-readable display name for this hierarchy node. Used in UI, visualizations, and taxonomy assignment results. NOT REQUIRED - When None: collection name or auto-generated label may be used. Format: Free text, typically title case, 2-50 characters. Examples: 'Executive Leadership', 'Mobile Phones', 'Engineering Team'. Can be LLM-generated or manually specified during taxonomy creation.")
    summary: Optional[StrictStr] = Field(default=None, description="OPTIONAL. Brief description of this hierarchy level and its contents. Used for: Documentation, UI tooltips, understanding hierarchy structure. NOT REQUIRED - When None: no summary available for this node. Format: Free text, typically 1-3 sentences, up to 500 characters. Can be LLM-generated or manually provided.")
    keywords: Optional[List[StrictStr]] = Field(default=None, description="OPTIONAL. Keywords or tags describing this hierarchy level. Used for: Search, filtering, categorization, LLM understanding. NOT REQUIRED - When None: no keywords defined for this node. Format: List of strings, typically 3-10 keywords per node. Can be LLM-generated from collection contents or manually specified.")
    retriever_id: Optional[Annotated[str, Field(strict=True)]] = Field(default=None, description="OPTIONAL. Retriever to use for matching documents at this hierarchy level. When None: Uses taxonomy-level retriever_id (inheritance from parent config). When set: Overrides taxonomy-level retriever for this specific node. Format: 'ret_' prefix followed by alphanumeric characters. Use for: Specialized matching at certain levels (e.g., face recognition for employees, semantic search for products). Must reference an existing RetrieverModel.")
    enrichment_fields: Optional[List[EnrichmentField]] = Field(default=None, description="OPTIONAL. Fields to enrich into documents when they match this hierarchy level. Specifies which properties from node collection to copy to matched documents. When None: No field-level enrichment (only taxonomy assignment recorded). Format: List of EnrichmentField objects with field_path and merge_mode. Inheritance: Child nodes inherit all parent enrichment_fields plus their own. Example: executives node adds 'executive_level' on top of inherited 'employee_id', 'department'.")
    input_mappings: Optional[List[InputMapping]] = Field(default=None, description="OPTIONAL. Custom input mappings for the retriever at this hierarchy level. Specifies how to construct retriever inputs from document features. When None: Uses taxonomy-level input_mappings (inheritance). When set: Overrides taxonomy-level mappings for this specific node. Format: List of InputMapping objects specifying input_key, source_type, path. Use for: Different matching strategies at different levels (e.g., face at employee level, text at department level).")
    __properties: ClassVar[List[str]] = ["collection_id", "parent_collection_id", "label", "summary", "keywords", "retriever_id", "enrichment_fields", "input_mappings"]

    @field_validator('collection_id')
    def collection_id_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if not re.match(r"^col_[a-zA-Z0-9_]+$", value):
            raise ValueError(r"must validate the regular expression /^col_[a-zA-Z0-9_]+$/")
        return value

    @field_validator('parent_collection_id')
    def parent_collection_id_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if value is None:
            return value

        if not re.match(r"^col_[a-zA-Z0-9_]+$", value):
            raise ValueError(r"must validate the regular expression /^col_[a-zA-Z0-9_]+$/")
        return value

    @field_validator('retriever_id')
    def retriever_id_validate_regular_expression(cls, value):
        """Validates the regular expression"""
        if value is None:
            return value

        if not re.match(r"^ret_[a-zA-Z0-9_]+$", value):
            raise ValueError(r"must validate the regular expression /^ret_[a-zA-Z0-9_]+$/")
        return value

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

    @classmethod
    def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
        """Create an instance of HierarchicalNodeInput 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"),
            "parent_collection_id": obj.get("parent_collection_id"),
            "label": obj.get("label"),
            "summary": obj.get("summary"),
            "keywords": obj.get("keywords"),
            "retriever_id": obj.get("retriever_id"),
            "enrichment_fields": [EnrichmentField.from_dict(_item) for _item in obj["enrichment_fields"]] if obj.get("enrichment_fields") is not None else None,
            "input_mappings": [InputMapping.from_dict(_item) for _item in obj["input_mappings"]] if obj.get("input_mappings") is not None else None
        })
        return _obj


