"""Tests for Tru-Guard execution strategies."""

import pytest
import asyncio

from trusys.execution.strategies import (
    ParallelStrategy,
    SequentialStrategy,
    PipelineStrategy,
    get_strategy_for_mode,
)
from trusys.types import ExecutionMode, ScanContext, ScanType


class TestParallelStrategy:
    """Tests for ParallelStrategy."""

    @pytest.mark.asyncio
    async def test_parallel_execution(self, simple_scanner_class):
        strategy = ParallelStrategy()
        scanners = [
            simple_scanner_class(should_pass=True),
            simple_scanner_class(should_pass=True),
        ]
        context = ScanContext(scan_type=ScanType.INPUT, prompt="test")

        results = await strategy.execute(scanners, "test", context)
        assert len(results) == 2
        assert all(r.passed for r in results)

    @pytest.mark.asyncio
    async def test_parallel_with_max_concurrent(self, simple_scanner_class):
        strategy = ParallelStrategy(max_concurrent=1)
        scanners = [
            simple_scanner_class(should_pass=True),
            simple_scanner_class(should_pass=True),
        ]
        context = ScanContext(scan_type=ScanType.INPUT, prompt="test")

        results = await strategy.execute(scanners, "test", context)
        assert len(results) == 2

    @pytest.mark.asyncio
    async def test_parallel_empty_scanners(self):
        strategy = ParallelStrategy()
        context = ScanContext(scan_type=ScanType.INPUT, prompt="test")

        results = await strategy.execute([], "test", context)
        assert len(results) == 0


class TestSequentialStrategy:
    """Tests for SequentialStrategy."""

    @pytest.mark.asyncio
    async def test_sequential_execution(self, simple_scanner_class):
        strategy = SequentialStrategy()
        scanners = [
            simple_scanner_class(should_pass=True),
            simple_scanner_class(should_pass=False),
        ]
        context = ScanContext(scan_type=ScanType.INPUT, prompt="test")

        results = await strategy.execute(scanners, "test", context)
        assert len(results) == 2
        assert results[0].passed is True
        assert results[1].passed is False


class TestPipelineStrategy:
    """Tests for PipelineStrategy."""

    @pytest.mark.asyncio
    async def test_pipeline_execution(self, fix_scanner_class):
        strategy = PipelineStrategy()
        scanners = [
            fix_scanner_class(find="bad", replace="good"),
            fix_scanner_class(find="ugly", replace="beautiful"),
        ]
        context = ScanContext(scan_type=ScanType.INPUT, prompt="bad and ugly")

        results = await strategy.execute(scanners, "bad and ugly", context)
        assert len(results) == 2

    @pytest.mark.asyncio
    async def test_pipeline_early_exit(self, simple_scanner_class):
        strategy = PipelineStrategy(early_exit=True)
        scanners = [
            simple_scanner_class(should_pass=False),
            simple_scanner_class(should_pass=True),
        ]
        context = ScanContext(scan_type=ScanType.INPUT, prompt="test")

        results = await strategy.execute(scanners, "test", context)
        assert len(results) == 1  # Stopped after first failure
        assert results[0].passed is False

    @pytest.mark.asyncio
    async def test_pipeline_no_early_exit(self, simple_scanner_class):
        strategy = PipelineStrategy(early_exit=False)
        scanners = [
            simple_scanner_class(should_pass=False),
            simple_scanner_class(should_pass=True),
        ]
        context = ScanContext(scan_type=ScanType.INPUT, prompt="test")

        results = await strategy.execute(scanners, "test", context)
        assert len(results) == 2  # Both scanners ran


class TestGetStrategyForMode:
    """Tests for get_strategy_for_mode function."""

    def test_get_parallel_strategy(self):
        strategy = get_strategy_for_mode(ExecutionMode.PARALLEL)
        assert isinstance(strategy, ParallelStrategy)

    def test_get_sequential_strategy(self):
        strategy = get_strategy_for_mode(ExecutionMode.SEQUENTIAL)
        assert isinstance(strategy, SequentialStrategy)

    def test_get_pipeline_strategy(self):
        strategy = get_strategy_for_mode(ExecutionMode.PIPELINE)
        assert isinstance(strategy, PipelineStrategy)

    def test_get_pipeline_with_early_exit(self):
        strategy = get_strategy_for_mode(ExecutionMode.PIPELINE, early_exit=True)
        assert isinstance(strategy, PipelineStrategy)
        assert strategy.early_exit is True

    def test_get_parallel_with_max_concurrent(self):
        strategy = get_strategy_for_mode(ExecutionMode.PARALLEL, max_concurrent=5)
        assert isinstance(strategy, ParallelStrategy)
        assert strategy.max_concurrent == 5
