from __future__ import annotations

from collections.abc import Mapping
from typing import Any, TypeVar, cast

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..models.agents_config_agent_api_type import AgentsConfigAgentApiType
from ..types import UNSET, Unset

T = TypeVar("T", bound="AgentsConfig")


@_attrs_define
class AgentsConfig:
    r"""Configuration for agent workflow.

    Attributes:
        enabled (bool | Unset): Whether to use agents mode for queries. Default: True.
        human_in_the_loop (bool | Unset): Enable the ask_user tool, allowing the agent to pause and ask the user a
            question with options. Default: True.
        web_search (bool | Unset): Enable web tools: web_search (find URLs) and read_url (fetch and process webpages).
            Default: True.
        mcp_tools (list[str] | Unset): MCP tool names to enable from LiteLLM (e.g. ['read_wiki_contents',
            'ask_question']).
        planning_enabled (bool | Unset): Run a planning step before the first agent decision. The agent generates a text
            plan that guides subsequent tool calls. Default: False.
        planning_approval (bool | Unset): When planning is enabled, pause after generating the plan to allow the user to
            approve, skip, or comment before proceeding. Requires PLANNING_ENABLED=True to have any effect. Default: False.
        suggested_queries (bool | Unset): Generate a single suggested follow-up query after each response. Default:
            False.
        persona (str | Unset): Agent persona prepended to the system prompt. Customise to change the agent's identity
            and tone. Default: 'You are ARBI, an AI assistant created by ARBI CITY.\n\nYou maintain formal, objective tone
            appropriate for professional/legal contexts. If any part of the answer is based on general knowledge instead of
            the supplied sources, you must state so clearly and recognise that it may not be accurate.'.
        agent_model_name (str | Unset): The name of the model to be used for the agent decision-making. Default:
            'dummy'.
        agent_api_type (AgentsConfigAgentApiType | Unset): The inference type for the agent LLM (local or remote).
            Default: AgentsConfigAgentApiType.REMOTE.
        llm_agent_temperature (float | Unset): Temperature value for agent LLM. Default: 0.7.
        agent_max_tokens (int | Unset): Maximum tokens for the agent LLM response. Default: 20000.
        agent_max_iterations (int | Unset): Maximum number of tool call iterations before forcing an answer. Default:
            10.
        agent_history_char_threshold (int | Unset): Char threshold for conversation history injected into the agent
            context. Below: verbatim user/assistant pairs. Above: summarized by SummariseLLM. Default: 8000.
        agent_system_prompt (str | Unset): System prompt for the agent. Dynamic context is appended automatically.
            Default: "YOUR TASK:\nAnswer the user's query using the best available source. Start by checking the workspace
            documents, but you can also use web search for real-time or external information, or draw on general knowledge
            when appropriate.\n\nTOOLS AVAILABLE:\nUse the tools provided to you. Each tool has its own
            description.\n\nANSWERING GUIDELINES:\n- If the answer comes from workspace documents, cite them normally.\n- If
            the answer comes from web search, state clearly that it is from the web.\n- If the answer is based on general
            knowledge (no tool results), state clearly\n  that it is based on general knowledge and may not be fully
            accurate.\n- You are allowed to answer questions that are not about the documents.\n\nEFFICIENCY GUIDELINES:\n1.
            PARALLEL CALLS: When a query has multiple aspects, call multiple tools in    parallel (e.g., search different
            keywords simultaneously)\n2. AVOID DUPLICATION: Before searching, review learnings from previous results.    Do
            not repeat searches for information you already have\n3. TARGETED SEARCHES: Use specific, focused queries rather
            than broad ones\n4. BROAD PASSAGE RANGES: When using get_document_passages, request broad ranges    (5-10+ pages
            per call). A few large fetches are far better than many small ones\n5. STOP WHEN READY: Provide your answer when
            you have sufficient evidence.    Signs you have enough:\n   - Multiple sources confirm the same facts\n   - Key
            questions from the query are addressed\n   - Additional searches return redundant information\n\nWORKFLOW:\n1.
            Analyze the query to identify distinct information needs\n2. Execute parallel searches for different aspects
            when appropriate\n3. Evaluate results - extract learnings, note gaps\n4. Only search again if specific gaps
            remain unfilled\n5. Answer when confident (no tool call) - do not over-research\n\nIMPORTANT:\n- The document
            index contains metadata only - you must retrieve actual content\n- Do not add inline citation markers - the
            system handles citations automatically".
    """

    enabled: bool | Unset = True
    human_in_the_loop: bool | Unset = True
    web_search: bool | Unset = True
    mcp_tools: list[str] | Unset = UNSET
    planning_enabled: bool | Unset = False
    planning_approval: bool | Unset = False
    suggested_queries: bool | Unset = False
    persona: str | Unset = (
        "You are ARBI, an AI assistant created by ARBI CITY.\n\nYou maintain formal, objective tone appropriate for professional/legal contexts. If any part of the answer is based on general knowledge instead of the supplied sources, you must state so clearly and recognise that it may not be accurate."
    )
    agent_model_name: str | Unset = "dummy"
    agent_api_type: AgentsConfigAgentApiType | Unset = AgentsConfigAgentApiType.REMOTE
    llm_agent_temperature: float | Unset = 0.7
    agent_max_tokens: int | Unset = 20000
    agent_max_iterations: int | Unset = 10
    agent_history_char_threshold: int | Unset = 8000
    agent_system_prompt: str | Unset = (
        "YOUR TASK:\nAnswer the user's query using the best available source. Start by checking the workspace documents, but you can also use web search for real-time or external information, or draw on general knowledge when appropriate.\n\nTOOLS AVAILABLE:\nUse the tools provided to you. Each tool has its own description.\n\nANSWERING GUIDELINES:\n- If the answer comes from workspace documents, cite them normally.\n- If the answer comes from web search, state clearly that it is from the web.\n- If the answer is based on general knowledge (no tool results), state clearly\n  that it is based on general knowledge and may not be fully accurate.\n- You are allowed to answer questions that are not about the documents.\n\nEFFICIENCY GUIDELINES:\n1. PARALLEL CALLS: When a query has multiple aspects, call multiple tools in    parallel (e.g., search different keywords simultaneously)\n2. AVOID DUPLICATION: Before searching, review learnings from previous results.    Do not repeat searches for information you already have\n3. TARGETED SEARCHES: Use specific, focused queries rather than broad ones\n4. BROAD PASSAGE RANGES: When using get_document_passages, request broad ranges    (5-10+ pages per call). A few large fetches are far better than many small ones\n5. STOP WHEN READY: Provide your answer when you have sufficient evidence.    Signs you have enough:\n   - Multiple sources confirm the same facts\n   - Key questions from the query are addressed\n   - Additional searches return redundant information\n\nWORKFLOW:\n1. Analyze the query to identify distinct information needs\n2. Execute parallel searches for different aspects when appropriate\n3. Evaluate results - extract learnings, note gaps\n4. Only search again if specific gaps remain unfilled\n5. Answer when confident (no tool call) - do not over-research\n\nIMPORTANT:\n- The document index contains metadata only - you must retrieve actual content\n- Do not add inline citation markers - the system handles citations automatically"
    )
    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> dict[str, Any]:
        enabled = self.enabled

        human_in_the_loop = self.human_in_the_loop

        web_search = self.web_search

        mcp_tools: list[str] | Unset = UNSET
        if not isinstance(self.mcp_tools, Unset):
            mcp_tools = self.mcp_tools

        planning_enabled = self.planning_enabled

        planning_approval = self.planning_approval

        suggested_queries = self.suggested_queries

        persona = self.persona

        agent_model_name = self.agent_model_name

        agent_api_type: str | Unset = UNSET
        if not isinstance(self.agent_api_type, Unset):
            agent_api_type = self.agent_api_type.value

        llm_agent_temperature = self.llm_agent_temperature

        agent_max_tokens = self.agent_max_tokens

        agent_max_iterations = self.agent_max_iterations

        agent_history_char_threshold = self.agent_history_char_threshold

        agent_system_prompt = self.agent_system_prompt

        field_dict: dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})
        if enabled is not UNSET:
            field_dict["ENABLED"] = enabled
        if human_in_the_loop is not UNSET:
            field_dict["HUMAN_IN_THE_LOOP"] = human_in_the_loop
        if web_search is not UNSET:
            field_dict["WEB_SEARCH"] = web_search
        if mcp_tools is not UNSET:
            field_dict["MCP_TOOLS"] = mcp_tools
        if planning_enabled is not UNSET:
            field_dict["PLANNING_ENABLED"] = planning_enabled
        if planning_approval is not UNSET:
            field_dict["PLANNING_APPROVAL"] = planning_approval
        if suggested_queries is not UNSET:
            field_dict["SUGGESTED_QUERIES"] = suggested_queries
        if persona is not UNSET:
            field_dict["PERSONA"] = persona
        if agent_model_name is not UNSET:
            field_dict["AGENT_MODEL_NAME"] = agent_model_name
        if agent_api_type is not UNSET:
            field_dict["AGENT_API_TYPE"] = agent_api_type
        if llm_agent_temperature is not UNSET:
            field_dict["LLM_AGENT_TEMPERATURE"] = llm_agent_temperature
        if agent_max_tokens is not UNSET:
            field_dict["AGENT_MAX_TOKENS"] = agent_max_tokens
        if agent_max_iterations is not UNSET:
            field_dict["AGENT_MAX_ITERATIONS"] = agent_max_iterations
        if agent_history_char_threshold is not UNSET:
            field_dict["AGENT_HISTORY_CHAR_THRESHOLD"] = agent_history_char_threshold
        if agent_system_prompt is not UNSET:
            field_dict["AGENT_SYSTEM_PROMPT"] = agent_system_prompt

        return field_dict

    @classmethod
    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
        d = dict(src_dict)
        enabled = d.pop("ENABLED", UNSET)

        human_in_the_loop = d.pop("HUMAN_IN_THE_LOOP", UNSET)

        web_search = d.pop("WEB_SEARCH", UNSET)

        mcp_tools = cast(list[str], d.pop("MCP_TOOLS", UNSET))

        planning_enabled = d.pop("PLANNING_ENABLED", UNSET)

        planning_approval = d.pop("PLANNING_APPROVAL", UNSET)

        suggested_queries = d.pop("SUGGESTED_QUERIES", UNSET)

        persona = d.pop("PERSONA", UNSET)

        agent_model_name = d.pop("AGENT_MODEL_NAME", UNSET)

        _agent_api_type = d.pop("AGENT_API_TYPE", UNSET)
        agent_api_type: AgentsConfigAgentApiType | Unset
        if isinstance(_agent_api_type, Unset):
            agent_api_type = UNSET
        else:
            agent_api_type = AgentsConfigAgentApiType(_agent_api_type)

        llm_agent_temperature = d.pop("LLM_AGENT_TEMPERATURE", UNSET)

        agent_max_tokens = d.pop("AGENT_MAX_TOKENS", UNSET)

        agent_max_iterations = d.pop("AGENT_MAX_ITERATIONS", UNSET)

        agent_history_char_threshold = d.pop("AGENT_HISTORY_CHAR_THRESHOLD", UNSET)

        agent_system_prompt = d.pop("AGENT_SYSTEM_PROMPT", UNSET)

        agents_config = cls(
            enabled=enabled,
            human_in_the_loop=human_in_the_loop,
            web_search=web_search,
            mcp_tools=mcp_tools,
            planning_enabled=planning_enabled,
            planning_approval=planning_approval,
            suggested_queries=suggested_queries,
            persona=persona,
            agent_model_name=agent_model_name,
            agent_api_type=agent_api_type,
            llm_agent_temperature=llm_agent_temperature,
            agent_max_tokens=agent_max_tokens,
            agent_max_iterations=agent_max_iterations,
            agent_history_char_threshold=agent_history_char_threshold,
            agent_system_prompt=agent_system_prompt,
        )

        agents_config.additional_properties = d
        return agents_config

    @property
    def additional_keys(self) -> list[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties
