from __future__ import annotations

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

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 the web_search tool for searching the web. 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:
            'Q3VL@ARBICITY'.
        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:\nDetermine which, if any, of the available documents contain information relevant to the
            user's query. Use your tools to retrieve and examine document content.\n\nTOOLS AVAILABLE:\n- search_documents:
            Search for relevant passages across documents\n- get_document_passages: Read specific pages from a document\n-
            get_table_of_contents: Get headings and page references for documents\n- web_search: Search the web for
            current/external information\n- ask_user: Ask the user a clarifying question with structured options.\n  You
            MUST call this tool to ask the user anything — do NOT write questions\n  or options as plain text. Only the tool
            delivers the question to the user.\n  IMPORTANT: Once the user responds, do NOT ask the same question again.\n
            Use their answer and proceed with research. If the user's answer is\n  unexpected (e.g. refers to something not
            in the documents), explain what\n  you found and answer based on available information.\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. 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 = 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 = "Q3VL@ARBICITY"
    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:\nDetermine which, if any, of the available documents contain information relevant to the user's query. Use your tools to retrieve and examine document content.\n\nTOOLS AVAILABLE:\n- search_documents: Search for relevant passages across documents\n- get_document_passages: Read specific pages from a document\n- get_table_of_contents: Get headings and page references for documents\n- web_search: Search the web for current/external information\n- ask_user: Ask the user a clarifying question with structured options.\n  You MUST call this tool to ask the user anything — do NOT write questions\n  or options as plain text. Only the tool delivers the question to the user.\n  IMPORTANT: Once the user responds, do NOT ask the same question again.\n  Use their answer and proceed with research. If the user's answer is\n  unexpected (e.g. refers to something not in the documents), explain what\n  you found and answer based on available information.\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. 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

        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 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)

        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,
            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
