"""Tests for kguru.utils module."""

import pytest

from kguru.utils import async_retry, extract_json


class TestExtractJson:
    def test_valid_json(self):
        text = '{"key": "value", "number": 42}'
        result = extract_json(text)
        assert result == {"key": "value", "number": 42}

    def test_empty_text(self):
        assert extract_json("") == {}
        assert extract_json("   ") == {}

    def test_json_with_surrounding_text(self):
        text = 'Some text before {"key": "value"} some text after'
        result = extract_json(text)
        assert result == {"key": "value"}

    def test_json_with_control_characters(self):
        text = '{"message": "Line 1\nLine 2\tTabbed"}'
        result = extract_json(text)
        assert result == {"message": "Line 1\nLine 2\tTabbed"}

    def test_invalid_json(self):
        text = "This is not JSON at all"
        result = extract_json(text)
        assert result == {}

    def test_malformed_json(self):
        text = '{"key": "value", "incomplete":'
        result = extract_json(text)
        assert result == {}


class TestAsyncRetry:
    @pytest.mark.asyncio
    async def test_successful_function(self):
        @async_retry(max_retries=3, delay=0.1)
        async def success_func():
            return "success"

        result = await success_func()
        assert result == "success"

    @pytest.mark.asyncio
    async def test_retry_on_failure(self):
        call_count = 0

        @async_retry(max_retries=3, delay=0.1)
        async def failing_func():
            nonlocal call_count
            call_count += 1
            if call_count < 3:
                raise ValueError("Test error")
            return "success"

        result = await failing_func()
        assert result == "success"
        assert call_count == 3

    @pytest.mark.asyncio
    async def test_max_retries_exceeded(self):
        @async_retry(max_retries=2, delay=0.1)
        async def always_fails():
            raise ValueError("Always fails")

        with pytest.raises(ValueError, match="Always fails"):
            await always_fails()

    @pytest.mark.asyncio
    async def test_function_with_args_kwargs(self):
        @async_retry(max_retries=2, delay=0.1)
        async def func_with_params(x, y, z=None):
            return f"{x}-{y}-{z}"

        result = await func_with_params("a", "b", z="c")
        assert result == "a-b-c"
