# Copyright (c) Microsoft. All rights reserved.

import contextlib
import datetime
import json
import logging
import os
from collections.abc import AsyncGenerator
from typing import Literal

import httpx
import pytest
import pytest_asyncio
from openai import AsyncOpenAI

from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion, OpenAISettings
from semantic_kernel.functions.kernel_arguments import KernelArguments
from semantic_kernel.functions.kernel_function import KernelFunction
from semantic_kernel.functions.kernel_function_decorator import kernel_function
from semantic_kernel.functions.kernel_function_from_method import KernelFunctionFromMethod
from semantic_kernel.functions.kernel_function_from_prompt import KernelFunctionFromPrompt
from semantic_kernel.kernel import Kernel
from semantic_kernel.prompt_template.prompt_template_config import PromptTemplateConfig

logger = logging.getLogger(__name__)

OPENAI_MODEL_ID = "gpt-4.1-nano"

# region Test Prompts

simple_prompt = "Can you help me tell the time in Seattle right now?"
sk_simple_prompt = "Can you help me tell the time in {{$city}} right now?"
hb_simple_prompt = "Can you help me tell the time in {{city}} right now?"
j2_simple_prompt = "Can you help me tell the time in {{city}} right now?"
sk_prompt = '<message role="system">The current time is {{Time.Now}}</message><message role="user">Can you help me tell the time in {{$city}} right now?</message>'  # noqa: E501
hb_prompt = '<message role="system">The current time is {{Time-Now}}</message><message role="user">Can you help me tell the time in {{city}} right now?</message>'  # noqa: E501
j2_prompt = '<message role="system">The current time is {{Time_Now()}}</message><message role="user">Can you help me tell the time in {{city}} right now?</message>'  # noqa: E501

# endregion

# region Custom Logging Class


class LoggingTransport(httpx.AsyncBaseTransport):
    def __init__(self, inner=None):
        self.inner = inner or httpx.AsyncHTTPTransport()
        self.request_headers = {}
        self.request_content = None
        self.response_headers = {}
        self.response_content = None

    async def handle_async_request(self, request: httpx.Request) -> httpx.Response:
        self.request_headers = dict(request.headers)
        self.request_content = request.content.decode("utf-8") if request.content else None

        logger.info(f"Request URL: {request.url}")
        logger.info(f"Request Headers: {self.request_headers}")
        logger.info(f"Request Content: {self.request_content}")

        response = await self.inner.handle_async_request(request)

        raw_response_bytes = await response.aread()
        self.response_headers = dict(response.headers)
        self.response_content = raw_response_bytes.decode(response.encoding or "utf-8", errors="replace")

        logger.info(f"Response Headers: {self.response_headers}")
        logger.info(f"Response Content: {self.response_content}")

        headers_without_encoding = {k: v for k, v in response.headers.items() if k.lower() != "content-encoding"}

        return httpx.Response(
            status_code=response.status_code,
            headers=headers_without_encoding,
            content=raw_response_bytes,
            request=request,
            extensions=response.extensions,
        )


class LoggingAsyncClient(httpx.AsyncClient):
    def __init__(self, *args, **kwargs):
        transport = kwargs.pop("transport", None)
        self.logging_transport = LoggingTransport(transport or httpx.AsyncHTTPTransport())
        super().__init__(*args, **kwargs, transport=self.logging_transport)

    @property
    def request_headers(self):
        return self.logging_transport.request_headers

    @property
    def request_content(self):
        return self.logging_transport.request_content

    @property
    def response_headers(self):
        return self.logging_transport.response_headers

    @property
    def response_content(self):
        return self.logging_transport.response_content


# endregion

# region Test Helper Methods


@pytest_asyncio.fixture
async def async_clients() -> AsyncGenerator[tuple[AsyncOpenAI, LoggingAsyncClient], None]:
    openai_settings = OpenAISettings()
    logging_async_client = LoggingAsyncClient()
    async with AsyncOpenAI(
        api_key=openai_settings.api_key.get_secret_value(), http_client=logging_async_client
    ) as client:
        yield client, logging_async_client


async def run_prompt(
    kernel: Kernel,
    is_inline: bool = False,
    is_streaming: bool = False,
    template_format: Literal[
        "semantic-kernel",
        "handlebars",
        "jinja2",
    ] = None,
    prompt: str = None,
    arguments: KernelArguments = None,
    prompt_template_config: PromptTemplateConfig = None,
):
    if is_inline:
        if is_streaming:
            try:
                async for _ in kernel.invoke_prompt_stream(
                    function_name="func_test_stream",
                    plugin_name="plugin_test",
                    prompt=prompt,
                    arguments=arguments,
                    template_format=template_format,
                    prompt_template_config=prompt_template_config,
                ):
                    pass
            except NotImplementedError:
                pass
        else:
            await kernel.invoke_prompt(
                function_name="func_test",
                plugin_name="plugin_test_stream",
                prompt=prompt,
                arguments=arguments,
                template_format=template_format,
                prompt_template_config=prompt_template_config,
            )
    else:
        function = KernelFunctionFromPrompt(
            function_name="test_func",
            plugin_name="test_plugin",
            prompt=prompt,
            template_format=template_format,
            prompt_template_config=prompt_template_config,
        )
        await run_function(kernel, is_streaming, function=function, arguments=arguments)


async def run_function(
    kernel: Kernel,
    is_streaming: bool = False,
    function: KernelFunction | None = None,
    arguments: KernelArguments | None = None,
):
    if is_streaming:
        try:
            async for _ in kernel.invoke_stream(function=function, arguments=arguments):
                pass
        except NotImplementedError:
            pass
    else:
        await kernel.invoke(function=function, arguments=arguments)


class City:
    def __init__(self, name):
        self.name = name


# endregion

# region Test Prompt With Chat Roles


@pytest.mark.parametrize(
    "is_inline, is_streaming, template_format, prompt",
    [
        pytest.param(
            True,
            False,
            "semantic-kernel",
            '<message role="user">Can you help me tell the time in Seattle right now?</message><message role="assistant">Sure! The time in Seattle is currently 3:00 PM.</message><message role="user">What about New York?</message>',  # noqa: E501
            id="sk_inline_non_streaming",
        ),
        pytest.param(
            True,
            True,
            "semantic-kernel",
            '<message role="user">Can you help me tell the time in Seattle right now?</message><message role="assistant">Sure! The time in Seattle is currently 3:00 PM.</message><message role="user">What about New York?</message>',  # noqa: E501
            id="sk_inline_streaming",
        ),
        pytest.param(
            False,
            False,
            "semantic-kernel",
            '<message role="user">Can you help me tell the time in Seattle right now?</message><message role="assistant">Sure! The time in Seattle is currently 3:00 PM.</message><message role="user">What about New York?</message>',  # noqa: E501
            id="sk_non_inline_non_streaming",
        ),
        pytest.param(
            False,
            True,
            "semantic-kernel",
            '<message role="user">Can you help me tell the time in Seattle right now?</message><message role="assistant">Sure! The time in Seattle is currently 3:00 PM.</message><message role="user">What about New York?</message>',  # noqa: E501
            id="sk_non_inline_streaming",
        ),
        pytest.param(
            False,
            False,
            "handlebars",
            '<message role="user">Can you help me tell the time in Seattle right now?</message><message role="assistant">Sure! The time in Seattle is currently 3:00 PM.</message><message role="user">What about New York?</message>',  # noqa: E501
            id="hb_non_inline_non_streaming",
        ),
        pytest.param(
            False,
            True,
            "handlebars",
            '<message role="user">Can you help me tell the time in Seattle right now?</message><message role="assistant">Sure! The time in Seattle is currently 3:00 PM.</message><message role="user">What about New York?</message>',  # noqa: E501
            id="hb_non_inline_streaming",
        ),
        pytest.param(
            False,
            False,
            "jinja2",
            '<message role="user">Can you help me tell the time in Seattle right now?</message><message role="assistant">Sure! The time in Seattle is currently 3:00 PM.</message><message role="user">What about New York?</message>',  # noqa: E501
            id="j2_non_inline_non_streaming",
        ),
        pytest.param(
            False,
            True,
            "jinja2",
            '<message role="user">Can you help me tell the time in Seattle right now?</message><message role="assistant">Sure! The time in Seattle is currently 3:00 PM.</message><message role="user">What about New York?</message>',  # noqa: E501
            id="j2_non_inline_streaming",
        ),
    ],
)
async def test_prompt_with_chat_roles(
    is_inline, is_streaming, template_format, prompt, async_clients: tuple[AsyncOpenAI, LoggingAsyncClient]
):
    client, logging_async_client = async_clients
    ai_service = OpenAIChatCompletion(
        service_id="test",
        ai_model_id=OPENAI_MODEL_ID,
        async_client=client,
    )

    kernel = Kernel()

    kernel.add_service(ai_service)

    await run_prompt(
        kernel=kernel,
        is_inline=is_inline,
        is_streaming=is_streaming,
        template_format=template_format,
        prompt=prompt,
    )

    request_content = logging_async_client.request_content
    assert request_content is not None

    response_content = logging_async_client.response_content
    assert response_content is not None

    obtained_object = json.loads(request_content)
    assert obtained_object is not None

    data_directory = os.path.join(os.path.dirname(__file__), "data", "prompt_with_chat_roles_expected.json")
    with open(data_directory) as f:
        expected = f.read()

    expected_object = json.loads(expected)
    assert expected_object is not None

    if is_streaming:
        expected_object["stream"] = True
        expected_object["stream_options"] = {"include_usage": True}

    assert obtained_object == expected_object


# endregion

# region Test Prompt With Complex Objects


@pytest.mark.parametrize(
    "is_inline, is_streaming, template_format, prompt",
    [
        pytest.param(
            False,
            False,
            "handlebars",
            "Can you help me tell the time in {{city.name}} right now?",
            id="hb_non_inline_non_streaming",
        ),
        pytest.param(
            False,
            True,
            "handlebars",
            "Can you help me tell the time in {{city.name}} right now?",
            id="hb_non_inline_streaming",
        ),
        pytest.param(
            False,
            False,
            "jinja2",
            "Can you help me tell the time in {{city.name}} right now?",
            id="j2_non_inline_non_streaming",
        ),
        pytest.param(
            False,
            True,
            "jinja2",
            "Can you help me tell the time in {{city.name}} right now?",
            id="j2_non_inline_streaming",
        ),
        pytest.param(
            True,
            False,
            "handlebars",
            "Can you help me tell the time in {{city.name}} right now?",
            id="hb_inline_non_streaming",
        ),
        pytest.param(
            True,
            True,
            "handlebars",
            "Can you help me tell the time in {{city.name}} right now?",
            id="hb_inline_streaming",
        ),
        pytest.param(
            True,
            False,
            "jinja2",
            "Can you help me tell the time in {{city.name}} right now?",
            id="j2_inline_non_streaming",
        ),
        pytest.param(
            True, True, "jinja2", "Can you help me tell the time in {{city.name}} right now?", id="j2_inline_streaming"
        ),
    ],
)
async def test_prompt_with_complex_objects(
    is_inline, is_streaming, template_format, prompt, async_clients: tuple[AsyncOpenAI, LoggingAsyncClient]
):
    client, logging_async_client = async_clients

    ai_service = OpenAIChatCompletion(
        service_id="default",
        ai_model_id=OPENAI_MODEL_ID,
        async_client=client,
    )

    kernel = Kernel()

    kernel.add_service(ai_service)

    await run_prompt(
        kernel=kernel,
        is_inline=is_inline,
        is_streaming=is_streaming,
        prompt=prompt,
        template_format=template_format,
        prompt_template_config=PromptTemplateConfig(
            template=prompt, template_format=template_format, allow_dangerously_set_content=True
        ),
        arguments=KernelArguments(city=City("Seattle")),
    )

    request_content = logging_async_client.request_content
    assert request_content is not None

    response_content = logging_async_client.response_content
    assert response_content is not None

    obtained_object = json.loads(request_content)
    assert obtained_object is not None

    data_directory = os.path.join(os.path.dirname(__file__), "data", "prompt_with_complex_objects_expected.json")
    with open(data_directory) as f:
        expected = f.read()

    expected_object = json.loads(expected)
    assert expected_object is not None

    if is_streaming:
        expected_object["stream"] = True
        expected_object["stream_options"] = {"include_usage": True}

    assert obtained_object == expected_object


# endregion

# region Test Prompt With Helper Functions


@pytest.mark.parametrize(
    "is_inline, is_streaming, template_format, prompt",
    [
        pytest.param(True, False, "semantic-kernel", sk_prompt, id="sk_inline_non_streaming"),
        pytest.param(True, True, "semantic-kernel", sk_prompt, id="sk_inline_streaming"),
        pytest.param(False, False, "semantic-kernel", sk_prompt, id="sk_non_inline_non_streaming"),
        pytest.param(False, True, "semantic-kernel", sk_prompt, id="sk_non_inline_streaming"),
        pytest.param(
            False,
            False,
            "handlebars",
            hb_prompt,
            id="hb_non_inline_non_streaming",
            marks=pytest.mark.xfail(reason="Throws intermittent APIConnectionError errors"),
        ),
        pytest.param(False, True, "handlebars", hb_prompt, id="hb_non_inline_streaming"),
        pytest.param(False, False, "jinja2", j2_prompt, id="j2_non_inline_non_streaming"),
        pytest.param(False, True, "jinja2", j2_prompt, id="j2_non_inline_streaming"),
    ],
)
async def test_prompt_with_helper_functions(
    is_inline, is_streaming, template_format, prompt, async_clients: tuple[AsyncOpenAI, LoggingAsyncClient]
):
    client, logging_async_client = async_clients

    ai_service = OpenAIChatCompletion(
        service_id="default",
        ai_model_id=OPENAI_MODEL_ID,
        async_client=client,
    )

    kernel = Kernel()

    kernel.add_service(ai_service)

    func = KernelFunctionFromMethod(
        method=kernel_function(
            lambda: datetime.datetime(1989, 6, 4, 12, 11, 13, tzinfo=datetime.timezone.utc).strftime(
                "%a, %d %b %Y %H:%M:%S GMT"
            ),
            name="Now",
        ),
        plugin_name="Time",
    )
    kernel.add_function(plugin_name="Time", function=func)

    await run_prompt(
        kernel=kernel,
        is_inline=is_inline,
        is_streaming=is_streaming,
        prompt=prompt,
        template_format=template_format,
        prompt_template_config=PromptTemplateConfig(
            template=prompt, template_format=template_format, allow_dangerously_set_content=True
        ),
        arguments=KernelArguments(city="Seattle"),
    )

    request_content = logging_async_client.request_content
    assert request_content is not None

    response_content = logging_async_client.response_content
    assert response_content is not None

    obtained_object = json.loads(request_content)
    assert obtained_object is not None

    data_directory = os.path.join(os.path.dirname(__file__), "data", "prompt_with_helper_functions_expected.json")
    with open(data_directory) as f:
        expected = f.read()

    expected_object = json.loads(expected)
    assert expected_object is not None

    if is_streaming:
        expected_object["stream"] = True
        expected_object["stream_options"] = {"include_usage": True}

    assert obtained_object == expected_object


# endregion

# region Test Prompt With Simple Variable


@pytest.mark.parametrize(
    "is_inline, is_streaming, template_format, prompt",
    [
        pytest.param(True, False, "semantic-kernel", sk_simple_prompt, id="sk_inline_non_streaming"),
        pytest.param(True, True, "semantic-kernel", sk_simple_prompt, id="sk_inline_streaming"),
        pytest.param(False, False, "semantic-kernel", sk_simple_prompt, id="sk_non_inline_non_streaming"),
        pytest.param(False, True, "semantic-kernel", sk_simple_prompt, id="sk_non_inline_streaming"),
        pytest.param(False, False, "handlebars", hb_simple_prompt, id="hb_non_inline_non_streaming"),
        pytest.param(False, True, "handlebars", hb_simple_prompt, id="hb_non_inline_streaming"),
        pytest.param(False, False, "jinja2", j2_simple_prompt, id="j2_non_inline_non_streaming"),
        pytest.param(False, True, "jinja2", j2_simple_prompt, id="j2_non_inline_streaming"),
    ],
)
async def test_prompt_with_simple_variable(
    is_inline, is_streaming, template_format, prompt, async_clients: tuple[AsyncOpenAI, LoggingAsyncClient]
):
    client, logging_async_client = async_clients

    ai_service = OpenAIChatCompletion(
        service_id="default",
        ai_model_id=OPENAI_MODEL_ID,
        async_client=client,
    )

    kernel = Kernel()

    kernel.add_service(ai_service)

    await run_prompt(
        kernel=kernel,
        is_inline=is_inline,
        is_streaming=is_streaming,
        template_format=template_format,
        prompt=prompt,
        arguments=KernelArguments(city="Seattle"),
    )

    request_content = logging_async_client.request_content
    assert request_content is not None

    response_content = logging_async_client.response_content
    assert response_content is not None

    obtained_object = json.loads(request_content)
    assert obtained_object is not None

    data_directory = os.path.join(os.path.dirname(__file__), "data", "prompt_with_simple_variable_expected.json")
    with open(data_directory) as f:
        expected = f.read()

    expected_object = json.loads(expected)
    assert expected_object is not None

    if is_streaming:
        expected_object["stream"] = True
        expected_object["stream_options"] = {"include_usage": True}

    assert obtained_object == expected_object


# endregion

# region Test Simple Prompt


@pytest.mark.parametrize(
    "is_inline, is_streaming, template_format, prompt",
    [
        pytest.param(True, False, "semantic-kernel", simple_prompt, id="sk_inline_non_streaming"),
        pytest.param(True, True, "semantic-kernel", simple_prompt, id="sk_inline_streaming"),
        pytest.param(False, False, "semantic-kernel", simple_prompt, id="sk_non_inline_non_streaming"),
        pytest.param(False, True, "semantic-kernel", simple_prompt, id="sk_non_inline_streaming"),
        pytest.param(False, False, "handlebars", simple_prompt, id="hb_non_inline_non_streaming"),
        pytest.param(False, True, "handlebars", simple_prompt, id="hb_non_inline_streaming"),
        pytest.param(False, False, "jinja2", simple_prompt, id="j2_non_inline_non_streaming"),
        pytest.param(False, True, "jinja2", simple_prompt, id="j2_non_inline_streaming"),
    ],
)
async def test_simple_prompt(
    is_inline, is_streaming, template_format, prompt, async_clients: tuple[AsyncOpenAI, LoggingAsyncClient]
):
    client, logging_async_client = async_clients

    ai_service = OpenAIChatCompletion(
        service_id="default",
        ai_model_id=OPENAI_MODEL_ID,
        async_client=client,
    )

    kernel = Kernel()

    kernel.add_service(ai_service)

    await run_prompt(
        kernel=kernel,
        is_inline=is_inline,
        is_streaming=is_streaming,
        template_format=template_format,
        prompt=prompt,
    )

    request_content = logging_async_client.request_content
    assert request_content is not None

    response_content = logging_async_client.response_content
    assert response_content is not None

    obtained_object = json.loads(request_content)
    assert obtained_object is not None

    data_directory = os.path.join(os.path.dirname(__file__), "data", "prompt_simple_expected.json")
    with open(data_directory) as f:
        expected = f.read()

    expected_object = json.loads(expected)
    assert expected_object is not None

    if is_streaming:
        expected_object["stream"] = True
        expected_object["stream_options"] = {"include_usage": True}

    assert obtained_object == expected_object


# endregion

# region Test YAML Prompts


@pytest.mark.parametrize(
    "is_streaming, prompt_path, expected_result_path",
    [
        pytest.param(
            False, "simple_prompt_test.yaml", "prompt_simple_expected.json", id="simple_prompt_test_non_streaming"
        ),
        pytest.param(True, "simple_prompt_test.yaml", "prompt_simple_expected.json", id="simple_prompt_test_streaming"),
        pytest.param(
            False,
            "prompt_with_chat_roles_test_hb.yaml",
            "prompt_with_chat_roles_expected.json",
            id="prompt_with_chat_roles_test_hb_non_streaming",
        ),
        pytest.param(
            True,
            "prompt_with_chat_roles_test_hb.yaml",
            "prompt_with_chat_roles_expected.json",
            id="prompt_with_chat_roles_test_hb_streaming",
        ),
        pytest.param(
            False,
            "prompt_with_chat_roles_test_j2.yaml",
            "prompt_with_chat_roles_expected.json",
            id="prompt_with_chat_roles_test_j2_non_streaming",
        ),
        pytest.param(
            True,
            "prompt_with_chat_roles_test_j2.yaml",
            "prompt_with_chat_roles_expected.json",
            id="prompt_with_chat_roles_test_j2_streaming",
        ),
        pytest.param(
            False,
            "prompt_with_simple_variable_test.yaml",
            "prompt_with_simple_variable_expected.json",
            id="prompt_with_simple_variable_non_streaming",
        ),
        pytest.param(
            True,
            "prompt_with_simple_variable_test.yaml",
            "prompt_with_simple_variable_expected.json",
            id="prompt_with_simple_variable_streaming",
        ),
    ],
)
async def test_yaml_prompt(
    is_streaming,
    prompt_path,
    expected_result_path,
    kernel: Kernel,
    async_clients: tuple[AsyncOpenAI, LoggingAsyncClient],
):
    client, logging_async_client = async_clients

    ai_service = OpenAIChatCompletion(
        service_id="default",
        ai_model_id=OPENAI_MODEL_ID,
        async_client=client,
    )

    kernel.add_service(ai_service)

    prompt_dir = os.path.join(os.path.dirname(__file__), "data", f"{prompt_path}")
    with open(prompt_dir) as f:
        prompt_str = f.read()
    function = KernelFunctionFromPrompt.from_yaml(yaml_str=prompt_str, plugin_name="yaml_plugin")

    await run_function(kernel=kernel, is_streaming=is_streaming, function=function)

    request_content = logging_async_client.request_content
    assert request_content is not None

    response_content = logging_async_client.response_content
    assert response_content is not None

    obtained_object = json.loads(request_content)
    assert obtained_object is not None

    data_directory = os.path.join(os.path.dirname(__file__), "data", f"{expected_result_path}")
    with open(data_directory) as f:
        expected = f.read()

    expected_object = json.loads(expected)
    assert expected_object is not None

    if is_streaming:
        expected_object["stream"] = True
        expected_object["stream_options"] = {"include_usage": True}

    assert obtained_object == expected_object


# endregion

# region Test OpenAPI Plugin Load


async def setup_openapi_function_call(kernel: Kernel, function_name, arguments):
    from semantic_kernel.connectors.openapi_plugin import OpenAPIFunctionExecutionParameters

    openapi_spec_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data", "light_bulb_api.json")

    request_details = None

    async def mock_request(request: httpx.Request):
        nonlocal request_details

        if request.method in ["POST", "PUT"]:
            request_body = None
            if request.content:
                request_body = request.content.decode()
            elif request.stream:
                try:
                    stream_content = await request.stream.read()
                    if stream_content:
                        request_body = stream_content.decode()
                except Exception:
                    request_body = None

            request_details = {
                "method": request.method,
                "url": str(request.url),
                "body": request_body,
                "headers": dict(request.headers),
            }
        else:
            request_details = {"method": request.method, "url": str(request.url), "params": dict(request.url.params)}

    transport = httpx.MockTransport(mock_request)

    async with httpx.AsyncClient(transport=transport) as client:
        plugin = kernel.add_plugin_from_openapi(
            plugin_name="LightControl",
            openapi_document_path=openapi_spec_file,
            execution_settings=OpenAPIFunctionExecutionParameters(
                http_client=client,
                server_url_validation_allowed_base_urls=["https://127.0.0.1"],
            ),
        )

        assert plugin is not None
        with contextlib.suppress(Exception):
            # It is expected that the API call will fail, ignore
            await run_function(kernel=kernel, is_streaming=False, function=plugin[function_name], arguments=arguments)

        return request_details


async def test_openapi_get_lights(kernel: Kernel):
    request_content = await setup_openapi_function_call(
        kernel, function_name="GetLights", arguments=KernelArguments(roomId=1)
    )

    assert request_content is not None

    assert request_content.get("method") == "GET"
    assert request_content.get("url") == "https://127.0.0.1/Lights?roomId=1"
    assert request_content.get("params") == {"roomId": "1"}


async def test_openapi_get_light_by_id(kernel: Kernel):
    request_content = await setup_openapi_function_call(
        kernel, function_name="GetLightById", arguments=KernelArguments(id=1)
    )

    assert request_content is not None

    assert request_content.get("method") == "GET"
    assert request_content.get("url") == "https://127.0.0.1/Lights/1"


async def test_openapi_delete_light_by_id(kernel: Kernel):
    request_content = await setup_openapi_function_call(
        kernel, function_name="DeleteLightById", arguments=KernelArguments(id=1)
    )

    assert request_content is not None

    assert request_content.get("method") == "DELETE"
    assert request_content.get("url") == "https://127.0.0.1/Lights/1"


async def test_openapi_create_lights(kernel: Kernel):
    request_content = await setup_openapi_function_call(
        kernel, function_name="CreateLights", arguments=KernelArguments(roomId=1, lightName="disco")
    )

    assert request_content is not None

    assert request_content.get("method") == "POST"
    assert request_content.get("url") == "https://127.0.0.1/Lights?roomId=1&lightName=disco"


async def test_openapi_put_light_by_id(kernel: Kernel):
    request_content = await setup_openapi_function_call(
        kernel, function_name="PutLightById", arguments=KernelArguments(id=1, hexColor="11EE11")
    )

    assert request_content is not None

    assert request_content.get("method") == "PUT"
    assert request_content.get("url") == "https://127.0.0.1/Lights/1"
    assert request_content.get("body") == '{"hexColor":"11EE11"}'


# endregion
