from dataclasses import dataclass
from typing import Self

from ntrp.channel import Channel
from ntrp.context.models import SessionState
from ntrp.core.agent import Agent
from ntrp.core.compactor import Compactor, SummaryCompactor
from ntrp.core.ledger import ResearchLedger
from ntrp.core.spawner import create_spawn_fn
from ntrp.tools.core.context import IOBridge, RunContext, ToolContext
from ntrp.tools.executor import ToolExecutor


@dataclass(frozen=True)
class AgentConfig:
    model: str
    research_model: str | None
    max_depth: int
    compactor: Compactor | None = None

    @classmethod
    def from_config(cls, config, *, model: str | None = None) -> Self:
        return cls(
            model=model or config.chat_model,
            research_model=config.research_model,
            max_depth=config.max_depth,
            compactor=SummaryCompactor(
                threshold=config.compression_threshold,
                max_messages=config.max_messages,
                keep_ratio=config.compression_keep_ratio,
                summary_max_tokens=config.summary_max_tokens,
            ),
        )


def create_agent(
    *,
    executor: ToolExecutor,
    config: AgentConfig,
    tools: list[dict],
    system_prompt: str | list[dict],
    session_state: SessionState,
    channel: Channel,
    run_id: str,
    io: IOBridge | None = None,
    extra_auto_approve: set[str] | None = None,
) -> Agent:
    run_ctx = RunContext(
        run_id=run_id,
        max_depth=config.max_depth,
        extra_auto_approve=extra_auto_approve or set(),
        research_model=config.research_model,
    )

    tool_ctx = ToolContext(
        session_state=session_state,
        registry=executor.registry,
        run=run_ctx,
        io=io or IOBridge(),
        services=executor.tool_services,
        channel=channel,
        ledger=ResearchLedger(),
    )
    tool_ctx.background_tasks.session_id = session_state.session_id
    tool_ctx.spawn_fn = create_spawn_fn(
        executor=executor,
        model=config.model,
        max_depth=config.max_depth,
        current_depth=0,
    )

    return Agent(
        tools=tools,
        tool_executor=executor,
        model=config.model,
        system_prompt=system_prompt,
        ctx=tool_ctx,
        max_depth=config.max_depth,
        current_depth=0,
        compactor=config.compactor,
    )
