# 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, StrictBool, StrictFloat, StrictInt, StrictStr
from typing import Any, ClassVar, Dict, List, Optional, Union
from typing_extensions import Annotated
from mixpeek.models.explain_stage_plan import ExplainStagePlan
from typing import Optional, Set
from typing_extensions import Self

class ExplainRetrieverResponse(BaseModel):
    """
    Execution plan analysis for a retriever.  Provides comprehensive diagnostics about retriever execution characteristics without actually running the query. Similar to MongoDB's explain plan or SQL's EXPLAIN command, this helps troubleshoot performance, estimate costs, and understand optimizer behavior.  Use Cases:     - Identify bottleneck stages before execution     - Estimate costs for budget planning     - Debug slow retrievers by analyzing stage efficiency     - Understand optimizer transformations     - Compare different retriever configurations     - Troubleshoot accuracy issues via document flow analysis
    """ # noqa: E501
    retriever_id: StrictStr = Field(description="Unique identifier of the retriever being explained. REQUIRED.")
    retriever_name: StrictStr = Field(description="Human-readable name of the retriever. REQUIRED.")
    estimated_cost: Dict[str, Union[StrictFloat, StrictInt]] = Field(description="Estimated total cost breakdown for executing this retriever. Contains: 'total_credits' (credit cost), 'total_duration_ms' (latency). Sum of all stage costs. Use for budget planning. REQUIRED.")
    execution_plan: Optional[List[ExplainStagePlan]] = Field(default=None, description="Ordered list of stage execution plans showing the OPTIMIZED pipeline. Each entry shows cost, latency, document flow, and warnings for one stage. Stages execute in this order. REQUIRED (may be empty for invalid retrievers).")
    optimization_suggestions: Optional[List[Dict[str, Any]]] = Field(default=None, description="Actionable suggestions for improving retriever performance. Each suggestion includes: 'type' (suggestion category), 'stage' (affected stage name), 'message' (human-readable description). Common types: 'reduce_limit', 'add_filter', 'reorder_stages', 'enable_cache'. OPTIONAL (empty if no suggestions).")
    total_estimated_stages: Annotated[int, Field(strict=True, ge=0)] = Field(description="Total number of stages in the optimized execution plan. This may differ from your original stage count if optimizations were applied. Compare with optimization_details.original_stage_count to see reduction. REQUIRED.")
    bottleneck_stages: Optional[List[StrictStr]] = Field(default=None, description="Names of stages expected to dominate execution time. Includes stages with duration >= 80%% of the slowest stage. Focus optimization efforts on these stages. OPTIONAL (empty if all stages have similar duration).")
    optimization_level: Optional[StrictStr] = Field(default='mvp', description="Optimization level applied by the optimizer. Values: 'none' (no optimization), 'mvp' (basic optimizations), 'advanced' (all optimizations). REQUIRED.")
    optimization_applied: Optional[StrictBool] = Field(default=False, description="Whether automatic pipeline optimizations were applied. When true, execution_plan shows OPTIMIZED stages (after transformations like filter push-down, stage fusion, grouping optimization). When false, execution_plan matches your original configuration. Check optimization_details to see what changed. REQUIRED.")
    optimization_details: Optional[Dict[str, Any]] = Field(default=None, description="Detailed breakdown of optimization transformations applied. Only present when optimization_applied=true.   Fields: - original_stage_count: Stage count before optimization - optimized_stage_count: Stage count after optimization - optimization_time_ms: Time spent on optimization (typically <100ms) - stage_reduction_pct: Percentage reduction in stage count - decisions: Array of optimization decisions   Each decision contains: - rule_type: Optimization rule that fired - applied: Whether the rule was applied - reason: Human-readable explanation - stages_before/after: Stage counts before/after this rule   Common rule types: - push_down_filters: Move filters earlier to reduce downstream work - group_by_push_down: Push grouping to database layer (10-100x faster) - merge_consecutive_filters: Combine adjacent filters - eliminate_redundant_sorts: Remove duplicate sort operations   OPTIONAL (null when optimization_applied=false).")
    __properties: ClassVar[List[str]] = ["retriever_id", "retriever_name", "estimated_cost", "execution_plan", "optimization_suggestions", "total_estimated_stages", "bottleneck_stages", "optimization_level", "optimization_applied", "optimization_details"]

    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 ExplainRetrieverResponse 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 execution_plan (list)
        _items = []
        if self.execution_plan:
            for _item_execution_plan in self.execution_plan:
                if _item_execution_plan:
                    _items.append(_item_execution_plan.to_dict())
            _dict['execution_plan'] = _items
        return _dict

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

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

        _obj = cls.model_validate({
            "retriever_id": obj.get("retriever_id"),
            "retriever_name": obj.get("retriever_name"),
            "estimated_cost": obj.get("estimated_cost"),
            "execution_plan": [ExplainStagePlan.from_dict(_item) for _item in obj["execution_plan"]] if obj.get("execution_plan") is not None else None,
            "optimization_suggestions": obj.get("optimization_suggestions"),
            "total_estimated_stages": obj.get("total_estimated_stages"),
            "bottleneck_stages": obj.get("bottleneck_stages"),
            "optimization_level": obj.get("optimization_level") if obj.get("optimization_level") is not None else 'mvp',
            "optimization_applied": obj.get("optimization_applied") if obj.get("optimization_applied") is not None else False,
            "optimization_details": obj.get("optimization_details")
        })
        return _obj


