# Copyright (c) Microsoft. All rights reserved.

"""Comprehensive tests for all confirmation strategies."""

import pytest

from agent_framework_ag_ui._confirmation_strategies import (
    ConfirmationStrategy,
    DefaultConfirmationStrategy,
    DocumentWriterConfirmationStrategy,
    RecipeConfirmationStrategy,
    TaskPlannerConfirmationStrategy,
)


@pytest.fixture
def sample_steps():
    """Sample steps for testing approval messages."""
    return [
        {"description": "Step 1: Do something", "status": "enabled"},
        {"description": "Step 2: Do another thing", "status": "enabled"},
        {"description": "Step 3: Disabled step", "status": "disabled"},
    ]


@pytest.fixture
def all_enabled_steps():
    """All steps enabled."""
    return [
        {"description": "Task A", "status": "enabled"},
        {"description": "Task B", "status": "enabled"},
        {"description": "Task C", "status": "enabled"},
    ]


@pytest.fixture
def empty_steps():
    """Empty steps list."""
    return []


class TestDefaultConfirmationStrategy:
    """Tests for DefaultConfirmationStrategy."""

    def test_on_approval_accepted_with_enabled_steps(self, sample_steps):
        strategy = DefaultConfirmationStrategy()
        message = strategy.on_approval_accepted(sample_steps)

        assert "Executing 2 approved steps" in message
        assert "Step 1: Do something" in message
        assert "Step 2: Do another thing" in message
        assert "Step 3" not in message  # Disabled step shouldn't appear
        assert "All steps completed successfully!" in message

    def test_on_approval_accepted_with_all_enabled(self, all_enabled_steps):
        strategy = DefaultConfirmationStrategy()
        message = strategy.on_approval_accepted(all_enabled_steps)

        assert "Executing 3 approved steps" in message
        assert "Task A" in message
        assert "Task B" in message
        assert "Task C" in message

    def test_on_approval_accepted_with_empty_steps(self, empty_steps):
        strategy = DefaultConfirmationStrategy()
        message = strategy.on_approval_accepted(empty_steps)

        assert "Executing 0 approved steps" in message
        assert "All steps completed successfully!" in message

    def test_on_approval_rejected(self, sample_steps):
        strategy = DefaultConfirmationStrategy()
        message = strategy.on_approval_rejected(sample_steps)

        assert "No problem!" in message
        assert "What would you like me to change" in message

    def test_on_state_confirmed(self):
        strategy = DefaultConfirmationStrategy()
        message = strategy.on_state_confirmed()

        assert "Changes confirmed" in message
        assert "successfully" in message

    def test_on_state_rejected(self):
        strategy = DefaultConfirmationStrategy()
        message = strategy.on_state_rejected()

        assert "No problem!" in message
        assert "What would you like me to change" in message


class TestTaskPlannerConfirmationStrategy:
    """Tests for TaskPlannerConfirmationStrategy."""

    def test_on_approval_accepted_with_enabled_steps(self, sample_steps):
        strategy = TaskPlannerConfirmationStrategy()
        message = strategy.on_approval_accepted(sample_steps)

        assert "Executing your requested tasks" in message
        assert "1. Step 1: Do something" in message
        assert "2. Step 2: Do another thing" in message
        assert "Step 3" not in message
        assert "All tasks completed successfully!" in message

    def test_on_approval_accepted_with_all_enabled(self, all_enabled_steps):
        strategy = TaskPlannerConfirmationStrategy()
        message = strategy.on_approval_accepted(all_enabled_steps)

        assert "Executing your requested tasks" in message
        assert "1. Task A" in message
        assert "2. Task B" in message
        assert "3. Task C" in message

    def test_on_approval_accepted_with_empty_steps(self, empty_steps):
        strategy = TaskPlannerConfirmationStrategy()
        message = strategy.on_approval_accepted(empty_steps)

        assert "Executing your requested tasks" in message
        assert "All tasks completed successfully!" in message

    def test_on_approval_rejected(self, sample_steps):
        strategy = TaskPlannerConfirmationStrategy()
        message = strategy.on_approval_rejected(sample_steps)

        assert "No problem!" in message
        assert "revise the plan" in message

    def test_on_state_confirmed(self):
        strategy = TaskPlannerConfirmationStrategy()
        message = strategy.on_state_confirmed()

        assert "Tasks confirmed" in message
        assert "ready to execute" in message

    def test_on_state_rejected(self):
        strategy = TaskPlannerConfirmationStrategy()
        message = strategy.on_state_rejected()

        assert "No problem!" in message
        assert "adjust the task list" in message


class TestRecipeConfirmationStrategy:
    """Tests for RecipeConfirmationStrategy."""

    def test_on_approval_accepted_with_enabled_steps(self, sample_steps):
        strategy = RecipeConfirmationStrategy()
        message = strategy.on_approval_accepted(sample_steps)

        assert "Updating your recipe" in message
        assert "1. Step 1: Do something" in message
        assert "2. Step 2: Do another thing" in message
        assert "Step 3" not in message
        assert "Recipe updated successfully!" in message

    def test_on_approval_accepted_with_all_enabled(self, all_enabled_steps):
        strategy = RecipeConfirmationStrategy()
        message = strategy.on_approval_accepted(all_enabled_steps)

        assert "Updating your recipe" in message
        assert "1. Task A" in message
        assert "2. Task B" in message
        assert "3. Task C" in message

    def test_on_approval_accepted_with_empty_steps(self, empty_steps):
        strategy = RecipeConfirmationStrategy()
        message = strategy.on_approval_accepted(empty_steps)

        assert "Updating your recipe" in message
        assert "Recipe updated successfully!" in message

    def test_on_approval_rejected(self, sample_steps):
        strategy = RecipeConfirmationStrategy()
        message = strategy.on_approval_rejected(sample_steps)

        assert "No problem!" in message
        assert "ingredients or steps" in message

    def test_on_state_confirmed(self):
        strategy = RecipeConfirmationStrategy()
        message = strategy.on_state_confirmed()

        assert "Recipe changes applied" in message
        assert "successfully" in message

    def test_on_state_rejected(self):
        strategy = RecipeConfirmationStrategy()
        message = strategy.on_state_rejected()

        assert "No problem!" in message
        assert "adjust in the recipe" in message


class TestDocumentWriterConfirmationStrategy:
    """Tests for DocumentWriterConfirmationStrategy."""

    def test_on_approval_accepted_with_enabled_steps(self, sample_steps):
        strategy = DocumentWriterConfirmationStrategy()
        message = strategy.on_approval_accepted(sample_steps)

        assert "Applying your edits" in message
        assert "1. Step 1: Do something" in message
        assert "2. Step 2: Do another thing" in message
        assert "Step 3" not in message
        assert "Document updated successfully!" in message

    def test_on_approval_accepted_with_all_enabled(self, all_enabled_steps):
        strategy = DocumentWriterConfirmationStrategy()
        message = strategy.on_approval_accepted(all_enabled_steps)

        assert "Applying your edits" in message
        assert "1. Task A" in message
        assert "2. Task B" in message
        assert "3. Task C" in message

    def test_on_approval_accepted_with_empty_steps(self, empty_steps):
        strategy = DocumentWriterConfirmationStrategy()
        message = strategy.on_approval_accepted(empty_steps)

        assert "Applying your edits" in message
        assert "Document updated successfully!" in message

    def test_on_approval_rejected(self, sample_steps):
        strategy = DocumentWriterConfirmationStrategy()
        message = strategy.on_approval_rejected(sample_steps)

        assert "No problem!" in message
        assert "keep or modify" in message

    def test_on_state_confirmed(self):
        strategy = DocumentWriterConfirmationStrategy()
        message = strategy.on_state_confirmed()

        assert "Document edits applied!" in message

    def test_on_state_rejected(self):
        strategy = DocumentWriterConfirmationStrategy()
        message = strategy.on_state_rejected()

        assert "No problem!" in message
        assert "change about the document" in message


class TestConfirmationStrategyInterface:
    """Tests for ConfirmationStrategy abstract base class."""

    def test_cannot_instantiate_abstract_class(self):
        """Verify ConfirmationStrategy is abstract and cannot be instantiated."""
        with pytest.raises(TypeError):
            ConfirmationStrategy()  # type: ignore

    def test_all_strategies_implement_interface(self):
        """Verify all concrete strategies implement the full interface."""
        strategies = [
            DefaultConfirmationStrategy(),
            TaskPlannerConfirmationStrategy(),
            RecipeConfirmationStrategy(),
            DocumentWriterConfirmationStrategy(),
        ]

        sample_steps = [{"description": "Test", "status": "enabled"}]

        for strategy in strategies:
            # All should have these methods
            assert callable(strategy.on_approval_accepted)
            assert callable(strategy.on_approval_rejected)
            assert callable(strategy.on_state_confirmed)
            assert callable(strategy.on_state_rejected)

            # All should return strings
            assert isinstance(strategy.on_approval_accepted(sample_steps), str)
            assert isinstance(strategy.on_approval_rejected(sample_steps), str)
            assert isinstance(strategy.on_state_confirmed(), str)
            assert isinstance(strategy.on_state_rejected(), str)
