# 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 mixpeek.models.sort_direction import SortDirection
from typing import Optional, Set
from typing_extensions import Self

class StageParamsSortRelevance(BaseModel):
    """
    Configuration for re-sorting documents by relevance score.  **Stage Category**: SORT  **Transformation**: N documents → N documents (same docs, different order, same schema)  **Purpose**: Reorders documents in the pipeline based on their relevance scores. This stage does NOT add/remove documents - it only changes their order.  **When to Use**:     - After SEARCH stages to reorder results by their similarity scores     - After multiple SEARCH stages are merged to apply final relevance ordering     - When you need to sort by a custom score field (not just top-level score)     - To apply consistent ordering after filtering operations  **When NOT to Use**:     - For initial document retrieval (use FILTER stages: hybrid_search)     - For removing documents (use FILTER stages: attribute_filter, llm_filter)     - For sorting by non-score attributes (use sort_attribute instead)     - For enriching documents (use APPLY stages)  **Operational Behavior**:     - Operates on in-memory document results (no database queries)     - Maintains all documents, just changes their order     - Fast operation (simple in-memory sort)     - Does not change document count or schema  **Common Pipeline Position**: FILTER → SORT (this stage) → APPLY  Requirements:     - score_field: OPTIONAL, defaults to \"score\"     - direction: OPTIONAL, defaults to descending (highest scores first)     - feature_address: OPTIONAL, for computing similarity when scores missing     - missing_score: OPTIONAL, controls placement of documents without scores  Use Cases:     - Standard relevance ranking: Sort search results by similarity scores     - Custom scoring: Sort by model-specific scores (metadata.rerank_score)     - Multi-stage pipelines: Final ordering after complex filtering     - Hybrid search: Order fused results by combined scores
    """ # noqa: E501
    score_field: Optional[StrictStr] = Field(default='score', description="OPTIONAL. Document field path to use for sorting. Defaults to top-level 'score' field populated by SEARCH stages. Use dot notation for nested fields (e.g., 'metadata.rerank_score'). Supports template expressions for dynamic field selection.")
    direction: Optional[SortDirection] = Field(default=None, description="OPTIONAL. Sort direction for relevance scores. 'desc' (default): Highest scores first (most relevant). 'asc': Lowest scores first (least relevant, rarely used).")
    feature_address: Optional[StrictStr] = Field(default='null', description="OPTIONAL. Feature address to compute similarity when scores are missing. If a document lacks the score_field, the system can compute similarity using this feature and the query embedding from earlier SEARCH stages. Format: 'mixpeek://extractor@version/output'. NOT REQUIRED - only use when expecting missing scores and want to compute them.")
    missing_score: Optional[StrictStr] = Field(default='bottom', description="OPTIONAL. How to handle documents without a score_field value. 'bottom' (default): Place at end of results (lowest priority). 'top': Place at start of results (highest priority, rarely used). 'preserve': Keep in original position (maintain insertion order).")
    __properties: ClassVar[List[str]] = ["score_field", "direction", "feature_address", "missing_score"]

    @field_validator('missing_score')
    def missing_score_validate_enum(cls, value):
        """Validates the enum"""
        if value is None:
            return value

        if value not in set(['bottom', 'top', 'preserve']):
            raise ValueError("must be one of enum values ('bottom', 'top', 'preserve')")
        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 StageParamsSortRelevance 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,
        )
        return _dict

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

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

        _obj = cls.model_validate({
            "score_field": obj.get("score_field") if obj.get("score_field") is not None else 'score',
            "direction": obj.get("direction"),
            "feature_address": obj.get("feature_address") if obj.get("feature_address") is not None else 'null',
            "missing_score": obj.get("missing_score") if obj.get("missing_score") is not None else 'bottom'
        })
        return _obj


