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.artifact_llm_config_api_type import ArtifactLLMConfigApiType
from ..types import UNSET, Unset

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


@_attrs_define
class ArtifactLLMConfig:
    r"""Configuration for ArtifactLLM - synthesizes document artifacts (skills, memories, reports).

    Produces markdown documents from gathered context (learnings, retrieval results,
    conversation history). Output is saved as a .txt document through the standard
    upload pipeline and linked to an assistant tag via DocTags.

    Note: The assistant tag relationship is stored on Configurations.tag_id (FK),
    not in this config. This config just controls synthesis behavior.

        Attributes:
            api_type (ArtifactLLMConfigApiType | Unset): The inference type (local or remote). Default:
                ArtifactLLMConfigApiType.REMOTE.
            model_name (str | Unset): The name of the non-reasoning model to be used. Default: 'Q3VL@ARBICITY'.
            enabled (bool | Unset): Whether to run artifact synthesis (skills, memories) after agent queries. Default: True.
            skill_system_instruction (str | Unset): System instruction for skill synthesis. Default: 'You are a skill
                synthesizer. You analyze work patterns, retrieval results, and conversation learnings to produce reusable
                procedural documents.\n\nGuidelines:\n- Create well-structured markdown with clear headings and numbered
                steps\n- Focus on reproducible procedures, not one-off observations\n- Include decision criteria, checklists,
                and edge cases where relevant\n- Be specific and actionable — another agent should be able to follow this
                skill\n- Ground everything in the provided context, do not invent information'.
            memory_system_instruction (str | Unset): System instruction for memory synthesis. Default: 'You are a knowledge
                recorder. You distill factual findings, preferences, and observations into concise reference
                documents.\n\nOutput format — use this markdown structure:\n```\n# [Descriptive Title]\n\n**Date:** [date from
                context]\n**Source:** [user query or conversation topic]\n\n## Key Findings\n[bullet points of facts
                learned]\n\n## Source Documents\n[list any document names referenced in the learnings]\n```\n\nGuidelines:\n-
                Record facts and observations, not procedures\n- Be concise — this is a reference document, not an essay\n-
                Always include the date and source query prominently\n- List source documents when learnings reference specific
                files\n- Distinguish between confirmed facts and inferences'.
            temperature (float | Unset): Temperature for synthesis. Default: 0.3.
            max_tokens (int | Unset): Maximum tokens for artifact content. Default: 4000.
            max_char_context (int | Unset): Maximum characters of input context. Default: 100000.
            max_concurrent (int | Unset): Maximum concurrent synthesis operations. Default: 5.
    """

    api_type: ArtifactLLMConfigApiType | Unset = ArtifactLLMConfigApiType.REMOTE
    model_name: str | Unset = "Q3VL@ARBICITY"
    enabled: bool | Unset = True
    skill_system_instruction: str | Unset = (
        "You are a skill synthesizer. You analyze work patterns, retrieval results, and conversation learnings to produce reusable procedural documents.\n\nGuidelines:\n- Create well-structured markdown with clear headings and numbered steps\n- Focus on reproducible procedures, not one-off observations\n- Include decision criteria, checklists, and edge cases where relevant\n- Be specific and actionable — another agent should be able to follow this skill\n- Ground everything in the provided context, do not invent information"
    )
    memory_system_instruction: str | Unset = (
        "You are a knowledge recorder. You distill factual findings, preferences, and observations into concise reference documents.\n\nOutput format — use this markdown structure:\n```\n# [Descriptive Title]\n\n**Date:** [date from context]\n**Source:** [user query or conversation topic]\n\n## Key Findings\n[bullet points of facts learned]\n\n## Source Documents\n[list any document names referenced in the learnings]\n```\n\nGuidelines:\n- Record facts and observations, not procedures\n- Be concise — this is a reference document, not an essay\n- Always include the date and source query prominently\n- List source documents when learnings reference specific files\n- Distinguish between confirmed facts and inferences"
    )
    temperature: float | Unset = 0.3
    max_tokens: int | Unset = 4000
    max_char_context: int | Unset = 100000
    max_concurrent: int | Unset = 5
    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> dict[str, Any]:
        api_type: str | Unset = UNSET
        if not isinstance(self.api_type, Unset):
            api_type = self.api_type.value

        model_name = self.model_name

        enabled = self.enabled

        skill_system_instruction = self.skill_system_instruction

        memory_system_instruction = self.memory_system_instruction

        temperature = self.temperature

        max_tokens = self.max_tokens

        max_char_context = self.max_char_context

        max_concurrent = self.max_concurrent

        field_dict: dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})
        if api_type is not UNSET:
            field_dict["API_TYPE"] = api_type
        if model_name is not UNSET:
            field_dict["MODEL_NAME"] = model_name
        if enabled is not UNSET:
            field_dict["ENABLED"] = enabled
        if skill_system_instruction is not UNSET:
            field_dict["SKILL_SYSTEM_INSTRUCTION"] = skill_system_instruction
        if memory_system_instruction is not UNSET:
            field_dict["MEMORY_SYSTEM_INSTRUCTION"] = memory_system_instruction
        if temperature is not UNSET:
            field_dict["TEMPERATURE"] = temperature
        if max_tokens is not UNSET:
            field_dict["MAX_TOKENS"] = max_tokens
        if max_char_context is not UNSET:
            field_dict["MAX_CHAR_CONTEXT"] = max_char_context
        if max_concurrent is not UNSET:
            field_dict["MAX_CONCURRENT"] = max_concurrent

        return field_dict

    @classmethod
    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
        d = dict(src_dict)
        _api_type = d.pop("API_TYPE", UNSET)
        api_type: ArtifactLLMConfigApiType | Unset
        if isinstance(_api_type, Unset):
            api_type = UNSET
        else:
            api_type = ArtifactLLMConfigApiType(_api_type)

        model_name = d.pop("MODEL_NAME", UNSET)

        enabled = d.pop("ENABLED", UNSET)

        skill_system_instruction = d.pop("SKILL_SYSTEM_INSTRUCTION", UNSET)

        memory_system_instruction = d.pop("MEMORY_SYSTEM_INSTRUCTION", UNSET)

        temperature = d.pop("TEMPERATURE", UNSET)

        max_tokens = d.pop("MAX_TOKENS", UNSET)

        max_char_context = d.pop("MAX_CHAR_CONTEXT", UNSET)

        max_concurrent = d.pop("MAX_CONCURRENT", UNSET)

        artifact_llm_config = cls(
            api_type=api_type,
            model_name=model_name,
            enabled=enabled,
            skill_system_instruction=skill_system_instruction,
            memory_system_instruction=memory_system_instruction,
            temperature=temperature,
            max_tokens=max_tokens,
            max_char_context=max_char_context,
            max_concurrent=max_concurrent,
        )

        artifact_llm_config.additional_properties = d
        return artifact_llm_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
