# Copyright (c) Microsoft. All rights reserved.

import copy
import os
from collections.abc import Awaitable, Callable
from typing import Any

import pytest
from pytest import MonkeyPatch, mark, param
from samples.getting_started.agents.azure_ai.azure_ai_basic import (
    main as azure_ai_basic,
)
from samples.getting_started.agents.azure_ai.azure_ai_with_code_interpreter import (
    main as azure_ai_with_code_interpreter,
)
from samples.getting_started.agents.azure_ai.azure_ai_with_existing_agent import (
    main as azure_ai_with_existing_agent,
)
from samples.getting_started.agents.azure_ai.azure_ai_with_explicit_settings import (
    main as azure_ai_with_explicit_settings,
)
from samples.getting_started.agents.azure_ai.azure_ai_with_function_tools import (
    mixed_tools_example as azure_ai_with_function_tools_mixed,
)
from samples.getting_started.agents.azure_ai.azure_ai_with_function_tools import (
    tools_on_agent_level as azure_ai_with_function_tools_agent,
)
from samples.getting_started.agents.azure_ai.azure_ai_with_function_tools import (
    tools_on_run_level as azure_ai_with_function_tools_run,
)
from samples.getting_started.agents.azure_ai.azure_ai_with_local_mcp import (
    main as azure_ai_with_local_mcp,
)
from samples.getting_started.agents.azure_ai.azure_ai_with_thread import (
    main as azure_ai_with_thread,
)
from samples.getting_started.agents.azure_openai.azure_assistants_basic import (
    main as azure_assistants_basic,
)
from samples.getting_started.agents.azure_openai.azure_assistants_with_code_interpreter import (
    main as azure_assistants_with_code_interpreter,
)
from samples.getting_started.agents.azure_openai.azure_assistants_with_existing_assistant import (
    main as azure_assistants_with_existing_assistant,
)
from samples.getting_started.agents.azure_openai.azure_assistants_with_explicit_settings import (
    main as azure_assistants_with_explicit_settings,
)
from samples.getting_started.agents.azure_openai.azure_assistants_with_function_tools import (
    main as azure_assistants_with_function_tools,
)
from samples.getting_started.agents.azure_openai.azure_assistants_with_thread import (
    main as azure_assistants_with_thread,
)
from samples.getting_started.agents.azure_openai.azure_chat_client_basic import (
    main as azure_chat_client_basic,
)
from samples.getting_started.agents.azure_openai.azure_chat_client_with_explicit_settings import (
    main as azure_chat_client_with_explicit_settings,
)
from samples.getting_started.agents.azure_openai.azure_chat_client_with_function_tools import (
    main as azure_chat_client_with_function_tools,
)
from samples.getting_started.agents.azure_openai.azure_chat_client_with_thread import (
    main as azure_chat_client_with_thread,
)
from samples.getting_started.agents.azure_openai.azure_responses_client_basic import (
    main as azure_responses_client_basic,
)
from samples.getting_started.agents.azure_openai.azure_responses_client_with_code_interpreter import (
    main as azure_responses_client_with_code_interpreter,
)
from samples.getting_started.agents.azure_openai.azure_responses_client_with_explicit_settings import (
    main as azure_responses_client_with_explicit_settings,
)
from samples.getting_started.agents.azure_openai.azure_responses_client_with_function_tools import (
    main as azure_responses_client_with_function_tools,
)
from samples.getting_started.agents.azure_openai.azure_responses_client_with_thread import (
    main as azure_responses_client_with_thread,
)
from samples.getting_started.agents.openai.openai_assistants_basic import (
    main as openai_assistants_basic,
)
from samples.getting_started.agents.openai.openai_assistants_with_code_interpreter import (
    main as openai_assistants_with_code_interpreter,
)
from samples.getting_started.agents.openai.openai_assistants_with_existing_assistant import (
    main as openai_assistants_with_existing_assistant,
)
from samples.getting_started.agents.openai.openai_assistants_with_explicit_settings import (
    main as openai_assistants_with_explicit_settings,
)
from samples.getting_started.agents.openai.openai_assistants_with_file_search import (
    main as openai_assistants_with_file_search,
)
from samples.getting_started.agents.openai.openai_assistants_with_function_tools import (
    main as openai_assistants_with_function_tools,
)
from samples.getting_started.agents.openai.openai_assistants_with_thread import (
    main as openai_assistants_with_thread,
)
from samples.getting_started.agents.openai.openai_chat_client_basic import (
    main as openai_chat_client_basic,
)
from samples.getting_started.agents.openai.openai_chat_client_with_explicit_settings import (
    main as openai_chat_client_with_explicit_settings,
)
from samples.getting_started.agents.openai.openai_chat_client_with_function_tools import (
    main as openai_chat_client_with_function_tools,
)
from samples.getting_started.agents.openai.openai_chat_client_with_local_mcp import (
    main as openai_chat_client_with_local_mcp,
)
from samples.getting_started.agents.openai.openai_chat_client_with_thread import (
    main as openai_chat_client_with_thread,
)
from samples.getting_started.agents.openai.openai_chat_client_with_web_search import (
    main as openai_chat_client_with_web_search,
)
from samples.getting_started.agents.openai.openai_responses_client_basic import (
    main as openai_responses_client_basic,
)
from samples.getting_started.agents.openai.openai_responses_client_reasoning import (
    main as openai_responses_client_reasoning,
)
from samples.getting_started.agents.openai.openai_responses_client_with_code_interpreter import (
    main as openai_responses_client_with_code_interpreter,
)
from samples.getting_started.agents.openai.openai_responses_client_with_explicit_settings import (
    main as openai_responses_client_with_explicit_settings,
)
from samples.getting_started.agents.openai.openai_responses_client_with_file_search import (
    main as openai_responses_client_with_file_search,
)
from samples.getting_started.agents.openai.openai_responses_client_with_function_tools import (
    main as openai_responses_client_with_function_tools,
)
from samples.getting_started.agents.openai.openai_responses_client_with_local_mcp import (
    main as openai_responses_client_with_local_mcp,
)
from samples.getting_started.agents.openai.openai_responses_client_with_thread import (
    main as openai_responses_client_with_thread,
)
from samples.getting_started.agents.openai.openai_responses_client_with_web_search import (
    main as openai_responses_client_with_web_search,
)

# Environment variable for controlling sample tests
RUN_SAMPLES_TESTS = "RUN_SAMPLES_TESTS"

# All agent samples across providers
agent_samples = [
    # Azure Assistants Agent samples
    param(
        azure_assistants_basic,
        [],  # Non-interactive sample
        id="azure_assistants_basic",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_assistants_with_code_interpreter,
        [],  # Non-interactive sample
        id="azure_assistants_with_code_interpreter",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_assistants_with_function_tools,
        [],  # Non-interactive sample
        id="azure_assistants_with_function_tools",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_assistants_with_existing_assistant,
        [],  # Non-interactive sample
        id="azure_assistants_with_existing_assistant",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_assistants_with_explicit_settings,
        [],  # Non-interactive sample
        id="azure_assistants_with_explicit_settings",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_assistants_with_thread,
        [],  # Non-interactive sample
        id="azure_assistants_with_thread",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    # Azure Chat Client Agent samples
    param(
        azure_chat_client_basic,
        [],  # Non-interactive sample
        id="azure_chat_client_basic",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_chat_client_with_explicit_settings,
        [],  # Non-interactive sample
        id="azure_chat_client_with_explicit_settings",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_chat_client_with_function_tools,
        [],  # Non-interactive sample
        id="azure_chat_client_with_function_tools",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_chat_client_with_thread,
        [],  # Non-interactive sample
        id="azure_chat_client_with_thread",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    # Azure Responses Client Agent samples
    param(
        azure_responses_client_basic,
        [],  # Non-interactive sample
        id="azure_responses_client_basic",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_responses_client_with_code_interpreter,
        [],  # Non-interactive sample
        id="azure_responses_client_with_code_interpreter",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_responses_client_with_explicit_settings,
        [],  # Non-interactive sample
        id="azure_responses_client_with_explicit_settings",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_responses_client_with_function_tools,
        [],  # Non-interactive sample
        id="azure_responses_client_with_function_tools",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_responses_client_with_thread,
        [],  # Non-interactive sample
        id="azure_responses_client_with_thread",
        marks=[
            pytest.mark.azure,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    # Azure AI Agent samples
    param(
        azure_ai_basic,
        [],  # Non-interactive sample
        id="azure_ai_basic",
        marks=[
            pytest.mark.azure_ai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_ai_with_code_interpreter,
        [],  # Non-interactive sample
        id="azure_ai_with_code_interpreter",
        marks=[
            pytest.mark.azure_ai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_ai_with_existing_agent,
        [],  # Non-interactive sample
        id="azure_ai_with_existing_agent",
        marks=[
            pytest.mark.azure_ai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_ai_with_explicit_settings,
        [],  # Non-interactive sample
        id="azure_ai_with_explicit_settings",
        marks=[
            pytest.mark.azure_ai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_ai_with_function_tools_agent,
        [],  # Non-interactive sample
        id="azure_ai_with_function_tools",
        marks=[
            pytest.mark.azure_ai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_ai_with_function_tools_run,
        [],  # Non-interactive sample
        id="azure_ai_with_function_tools",
        marks=[
            pytest.mark.azure_ai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_ai_with_function_tools_mixed,
        [],  # Non-interactive sample
        id="azure_ai_with_function_tools",
        marks=[
            pytest.mark.azure_ai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_ai_with_thread,
        [],  # Non-interactive sample
        id="azure_ai_with_thread",
        marks=[
            pytest.mark.azure_ai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        azure_ai_with_local_mcp,
        [],  # Non-interactive sample
        id="azure_ai_with_local_mcp",
        marks=[
            pytest.mark.azure_ai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    # OpenAI Assistants Agent samples
    param(
        openai_assistants_basic,
        [],  # Non-interactive sample
        id="openai_assistants_basic",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_assistants_with_code_interpreter,
        [],  # Non-interactive sample
        id="openai_assistants_with_code_interpreter",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_assistants_with_existing_assistant,
        [],  # Non-interactive sample
        id="openai_assistants_with_existing_assistant",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_assistants_with_explicit_settings,
        [],  # Non-interactive sample
        id="openai_assistants_with_explicit_settings",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_assistants_with_file_search,
        [],  # Non-interactive sample
        id="openai_assistants_with_file_search",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
            pytest.mark.skip(reason="OpenAI file search functionality is currently broken - tracked in GitHub issue"),
        ],
    ),
    param(
        openai_assistants_with_function_tools,
        [],  # Non-interactive sample
        id="openai_assistants_with_function_tools",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_assistants_with_thread,
        [],  # Non-interactive sample
        id="openai_assistants_with_thread",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    # OpenAI Chat Client Agent samples
    param(
        openai_chat_client_basic,
        [],  # Non-interactive sample
        id="openai_chat_client_basic",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_chat_client_with_explicit_settings,
        [],  # Non-interactive sample
        id="openai_chat_client_with_explicit_settings",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_chat_client_with_function_tools,
        [],  # Non-interactive sample
        id="openai_chat_client_with_function_tools",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_chat_client_with_local_mcp,
        [],  # Non-interactive sample
        id="openai_chat_client_with_local_mcp",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_chat_client_with_thread,
        [],  # Non-interactive sample
        id="openai_chat_client_with_thread",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_chat_client_with_web_search,
        [],  # Non-interactive sample
        id="openai_chat_client_with_web_search",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    # OpenAI Responses Client Agent samples
    param(
        openai_responses_client_basic,
        [],  # Non-interactive sample
        id="openai_responses_client_basic",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_responses_client_reasoning,
        [],  # Non-interactive sample
        id="openai_responses_client_reasoning",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_responses_client_with_code_interpreter,
        [],  # Non-interactive sample
        id="openai_responses_client_with_code_interpreter",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_responses_client_with_explicit_settings,
        [],  # Non-interactive sample
        id="openai_responses_client_with_explicit_settings",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_responses_client_with_file_search,
        [],  # Non-interactive sample
        id="openai_responses_client_with_file_search",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
            pytest.mark.skip(reason="OpenAI file search functionality is currently broken - tracked in GitHub issue"),
        ],
    ),
    param(
        openai_responses_client_with_function_tools,
        [],  # Non-interactive sample
        id="openai_responses_client_with_function_tools",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_responses_client_with_local_mcp,
        [],  # Non-interactive sample
        id="openai_responses_client_with_local_mcp",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_responses_client_with_thread,
        [],  # Non-interactive sample
        id="openai_responses_client_with_thread",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
    param(
        openai_responses_client_with_web_search,
        [],  # Non-interactive sample
        id="openai_responses_client_with_web_search",
        marks=[
            pytest.mark.openai,
            pytest.mark.skipif(os.getenv(RUN_SAMPLES_TESTS, None) is None, reason="Not running sample tests."),
        ],
    ),
]


@pytest.mark.flaky
@mark.parametrize("sample, responses", agent_samples)
async def test_agent_samples(sample: Callable[..., Awaitable[Any]], responses: list[str], monkeypatch: MonkeyPatch):
    """Test agent samples with input mocking and retry logic."""
    saved_responses = copy.deepcopy(responses)

    def reset():
        responses.clear()
        responses.extend(saved_responses)

    def mock_input(prompt: str = "") -> str:
        return responses.pop(0) if responses else "exit"

    monkeypatch.setattr("builtins.input", mock_input)
    await sample
