#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -------------------------------------------------------------------------
# Copyright (c) 2026 Huawei Technologies Co., Ltd.
# This file is part of the MindStudio project.
#
# MindStudio is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#
#    http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# -------------------------------------------------------------------------

from __future__ import annotations

import asyncio
import inspect

import pytest
from langchain_core.tools import ToolException, tool

from msagent.configs import LLMConfig, ToolsConfig
from msagent.tools.catalog.skills import fetch_skills
from msagent.tools.factory import ToolFactory


def test_default_timeout_settings_are_applied() -> None:
    llm = LLMConfig(
        provider="openai",
        model="gpt-5.4",
        alias="default",
        max_tokens=0,
        temperature=0.0,
        streaming=True,
    )
    tools = ToolsConfig()

    assert llm.request_timeout_seconds == 120
    assert tools.execution_timeout_seconds == 300


@tool("slow_tool")
async def _slow_tool(*, seconds: float = 0.2) -> str:
    """Sleep for a while and return done."""
    await asyncio.sleep(seconds)
    return "done"


@pytest.mark.asyncio
async def test_tool_factory_wraps_timeout_with_user_readable_error() -> None:
    wrapped = ToolFactory().wrap_tool_with_timeout(
        _slow_tool,
        timeout_seconds=0.05,
        source="unit-test",
    )

    with pytest.raises(ToolException, match="timed out after 0s|timed out after 1s|timed out"):
        await wrapped.ainvoke({"seconds": 0.2})


def test_timeout_wrapper_preserves_runtime_parameter_for_injected_context() -> None:
    wrapped = ToolFactory().wrap_tool_with_timeout(
        fetch_skills,
        timeout_seconds=1.0,
        source="unit-test",
    )

    assert wrapped.coroutine is not None
    assert "runtime" in inspect.signature(wrapped.coroutine).parameters