"""
Tests for ApeTask - Task representation and JSON Schema conversion.
"""

import pytest
from unittest.mock import Mock, MagicMock

from ape_langchain.task import ApeTask
from ape_langchain.core import ApeModule


def test_ape_task_creation():
    """Test creating an ApeTask directly."""
    task = ApeTask(
        name="add",
        inputs={"a": "str", "b": "str"},
        output="str",
        description="Add two numbers"
    )
    
    assert task.name == "add"
    assert task.inputs == {"a": "str", "b": "str"}
    assert task.output == "str"
    assert task.description == "Add two numbers"


def test_ape_task_from_module():
    """Test extracting ApeTask from a compiled module."""
    # Mock ApeModule and FunctionSignature
    mock_signature = Mock()
    mock_signature.name = "calculate"
    mock_signature.inputs = {"x": "str", "y": "str"}
    mock_signature.output = "str"
    mock_signature.description = "Calculate something"
    
    mock_module = Mock(spec=ApeModule)
    mock_module.get_function_signature.return_value = mock_signature
    
    # Extract task
    task = ApeTask.from_module(mock_module, "calculate")
    
    assert task.name == "calculate"
    assert task.inputs == {"x": "str", "y": "str"}
    assert task.output == "str"
    assert task.description == "Calculate something"
    mock_module.get_function_signature.assert_called_once_with("calculate")


def test_ape_task_to_json_schema():
    """Test JSON Schema conversion."""
    task = ApeTask(
        name="multiply",
        inputs={"a": "str", "b": "str"},
        output="str"
    )
    
    schema = task.to_json_schema()
    
    assert schema["type"] == "function"
    assert schema["function"]["name"] == "multiply"
    assert "parameters" in schema["function"]
    
    params = schema["function"]["parameters"]
    assert params["type"] == "object"
    assert "a" in params["properties"]
    assert "b" in params["properties"]
    assert params["properties"]["a"]["type"] == "string"
    assert params["properties"]["b"]["type"] == "string"
    assert set(params["required"]) == {"a", "b"}


def test_ape_task_validate_inputs_success():
    """Test input validation with valid inputs."""
    task = ApeTask(
        name="divide",
        inputs={"numerator": "str", "denominator": "str"}
    )
    
    # Should not raise
    task.validate_inputs(numerator="10", denominator="2")


def test_ape_task_validate_inputs_missing():
    """Test input validation with missing parameters."""
    task = ApeTask(
        name="divide",
        inputs={"numerator": "str", "denominator": "str"}
    )
    
    with pytest.raises(TypeError, match="Missing required parameters"):
        task.validate_inputs(numerator="10")


def test_ape_task_validate_inputs_unexpected():
    """Test input validation with unexpected parameters."""
    task = ApeTask(
        name="divide",
        inputs={"numerator": "str", "denominator": "str"}
    )
    
    with pytest.raises(TypeError, match="Unexpected parameters"):
        task.validate_inputs(numerator="10", denominator="2", extra="oops")


def test_ape_task_repr():
    """Test string representation."""
    task = ApeTask(
        name="subtract",
        inputs={"a": "int", "b": "int"},
        output="int"
    )
    
    repr_str = repr(task)
    assert "subtract" in repr_str
    assert "a: int" in repr_str
    assert "b: int" in repr_str
    assert "-> int" in repr_str


def test_ape_task_json_schema_with_types():
    """Test JSON Schema with different type mappings."""
    task = ApeTask(
        name="complex_calc",
        inputs={
            "name": "str",
            "count": "int",
            "rate": "float",
            "enabled": "bool"
        }
    )
    
    schema = task.to_json_schema()
    props = schema["function"]["parameters"]["properties"]
    
    assert props["name"]["type"] == "string"
    assert props["count"]["type"] == "integer"
    assert props["rate"]["type"] == "number"
    assert props["enabled"]["type"] == "boolean"
