"""Unit tests for debate framework.

Tests the DebateFramework, Argument, Rebuttal, and DebateResult classes.
"""

import pytest

from openclaw.debate.debate_framework import (
    Argument,
    ArgumentStrength,
    ArgumentType,
    DebateConfig,
    DebateFramework,
    DebateResult,
    DebateRound,
    Rebuttal,
)


class TestArgument:
    """Test Argument dataclass."""

    def test_argument_creation(self):
        """Test creating an argument."""
        arg = Argument(
            agent_id="bull-1",
            argument_type=ArgumentType.BULLISH,
            claim="Revenue is growing rapidly",
            evidence="20% YoY growth in Q3",
            strength=ArgumentStrength.STRONG,
            target_factors=["revenue", "growth"],
        )

        assert arg.agent_id == "bull-1"
        assert arg.argument_type == ArgumentType.BULLISH
        assert arg.claim == "Revenue is growing rapidly"
        assert arg.strength == ArgumentStrength.STRONG
        assert "revenue" in arg.target_factors

    def test_argument_to_dict(self):
        """Test converting argument to dictionary."""
        arg = Argument(
            agent_id="bear-1",
            argument_type=ArgumentType.BEARISH,
            claim="Competition is increasing",
            evidence="Market share declining 5%",
            strength=ArgumentStrength.MODERATE,
        )

        d = arg.to_dict()
        assert d["agent_id"] == "bear-1"
        assert d["argument_type"] == "bearish"
        assert "timestamp" in d


class TestRebuttal:
    """Test Rebuttal dataclass."""

    @pytest.fixture
    def target_argument(self):
        """Create a target argument for rebuttal."""
        return Argument(
            agent_id="bull-1",
            argument_type=ArgumentType.BULLISH,
            claim="PE ratio is reasonable",
            evidence="PE is 15 vs industry 20",
            strength=ArgumentStrength.MODERATE,
        )

    def test_rebuttal_creation(self, target_argument):
        """Test creating a rebuttal."""
        rebuttal = Rebuttal(
            agent_id="bear-1",
            target_argument=target_argument,
            counter_claim="PE doesn't account for debt",
            reasoning="High debt load makes PE misleading",
            effectiveness=0.7,
        )

        assert rebuttal.agent_id == "bear-1"
        assert rebuttal.effectiveness == 0.7
        assert rebuttal.target_argument == target_argument

    def test_rebuttal_effectiveness_clamping(self, target_argument):
        """Test that effectiveness is clamped to 0-1 range."""
        rebuttal_high = Rebuttal(
            agent_id="bear-1",
            target_argument=target_argument,
            counter_claim="Test",
            reasoning="Test",
            effectiveness=1.5,
        )
        assert rebuttal_high.effectiveness == 1.0

        rebuttal_low = Rebuttal(
            agent_id="bear-1",
            target_argument=target_argument,
            counter_claim="Test",
            reasoning="Test",
            effectiveness=-0.5,
        )
        assert rebuttal_low.effectiveness == 0.0


class TestDebateRound:
    """Test DebateRound class."""

    @pytest.fixture
    def round_data(self):
        """Create a debate round."""
        return DebateRound(round_number=1)

    def test_add_argument(self, round_data):
        """Test adding arguments to a round."""
        arg = Argument(
            agent_id="bull-1",
            argument_type=ArgumentType.BULLISH,
            claim="Growth is strong",
            evidence="20% YoY",
            strength=ArgumentStrength.STRONG,
        )
        round_data.add_argument(arg)

        assert len(round_data.arguments) == 1
        assert round_data.arguments[0] == arg

    def test_get_bullish_arguments(self, round_data):
        """Test filtering bullish arguments."""
        bull_arg = Argument(
            agent_id="bull-1",
            argument_type=ArgumentType.BULLISH,
            claim="Buy",
            evidence="Growth",
            strength=ArgumentStrength.STRONG,
        )
        bear_arg = Argument(
            agent_id="bear-1",
            argument_type=ArgumentType.BEARISH,
            claim="Sell",
            evidence="Risk",
            strength=ArgumentStrength.MODERATE,
        )

        round_data.add_argument(bull_arg)
        round_data.add_argument(bear_arg)

        bullish = round_data.get_bullish_arguments()
        assert len(bullish) == 1
        assert bullish[0].argument_type == ArgumentType.BULLISH


class TestDebateConfig:
    """Test DebateConfig validation."""

    def test_valid_config(self):
        """Test valid configuration."""
        config = DebateConfig(max_rounds=5, min_rounds=2)
        assert config.max_rounds == 5
        assert config.min_rounds == 2

    def test_invalid_max_rounds(self):
        """Test that max_rounds < min_rounds raises error."""
        with pytest.raises(ValueError):
            DebateConfig(max_rounds=1, min_rounds=2)

    def test_invalid_consensus_threshold(self):
        """Test that invalid consensus threshold raises error."""
        with pytest.raises(ValueError):
            DebateConfig(consensus_threshold=1.5)


class TestDebateFramework:
    """Test DebateFramework functionality."""

    @pytest.fixture
    def framework(self):
        """Create a debate framework."""
        config = DebateConfig(max_rounds=3, min_rounds=1)
        return DebateFramework(config)

    def test_start_debate(self, framework):
        """Test starting a debate."""
        framework.start_debate("AAPL")
        assert framework.symbol == "AAPL"
        assert len(framework.rounds) == 0

    def test_add_round(self, framework):
        """Test adding debate rounds."""
        framework.start_debate("AAPL")
        round1 = framework.add_round()
        round2 = framework.add_round()

        assert round1.round_number == 1
        assert round2.round_number == 2
        assert len(framework.rounds) == 2

    def test_submit_argument(self, framework):
        """Test submitting arguments."""
        framework.start_debate("AAPL")
        argument = framework.submit_argument(
            agent_id="bull-1",
            argument_type=ArgumentType.BULLISH,
            claim="Strong growth",
            evidence="20% YoY",
            strength=ArgumentStrength.STRONG,
        )

        assert argument.agent_id == "bull-1"
        assert len(framework.rounds) == 1
        assert len(framework.rounds[0].arguments) == 1

    def test_calculate_scores(self, framework):
        """Test score calculation."""
        framework.start_debate("AAPL")
        framework.add_round()

        # Add bullish argument
        framework.submit_argument(
            agent_id="bull-1",
            argument_type=ArgumentType.BULLISH,
            claim="Growth",
            evidence="Data",
            strength=ArgumentStrength.STRONG,
        )

        bull_score, bear_score = framework._calculate_scores()
        assert bull_score > 0
        assert bear_score == 0

    def test_conclude_debate_bull_wins(self, framework):
        """Test concluding debate with bull win."""
        framework.start_debate("AAPL")
        framework.add_round()

        # Strong bullish argument
        framework.submit_argument(
            agent_id="bull-1",
            argument_type=ArgumentType.BULLISH,
            claim="Strong growth",
            evidence="20% YoY",
            strength=ArgumentStrength.COMPELLING,
        )

        result = framework.conclude_debate()

        assert result.symbol == "AAPL"
        assert result.winner == "bull"
        assert result.recommendation == "buy"
        assert result.bull_score > result.bear_score

    def test_conclude_debate_bear_wins(self, framework):
        """Test concluding debate with bear win."""
        framework.start_debate("AAPL")
        framework.add_round()

        # Strong bearish argument
        framework.submit_argument(
            agent_id="bear-1",
            argument_type=ArgumentType.BEARISH,
            claim="High risk",
            evidence="Debt increasing",
            strength=ArgumentStrength.COMPELLING,
        )

        result = framework.conclude_debate()

        assert result.winner == "bear"
        assert result.recommendation == "sell"

    def test_should_continue_max_rounds(self, framework):
        """Test should_continue respects max_rounds."""
        framework.start_debate("AAPL")
        framework.add_round()
        framework.add_round()
        framework.add_round()

        assert not framework.should_continue()

    def test_rebuttal_reduces_score(self, framework):
        """Test that rebuttals reduce target argument scores."""
        framework.start_debate("AAPL")
        framework.add_round()

        # Submit bullish argument
        argument = framework.submit_argument(
            agent_id="bull-1",
            argument_type=ArgumentType.BULLISH,
            claim="Strong moat",
            evidence="Market leader",
            strength=ArgumentStrength.STRONG,
        )

        # Rebut it
        framework.submit_rebuttal(
            agent_id="bear-1",
            target_argument=argument,
            counter_claim="Moat is eroding",
            reasoning="New competitors emerging",
            effectiveness=0.8,
        )

        bull_score, _ = framework._calculate_scores()
        # Score should be reduced by rebuttal
        assert bull_score < 40  # Strong argument is 40, reduced by 80%


class TestDebateResult:
    """Test DebateResult dataclass."""

    def test_result_creation(self):
        """Test creating a debate result."""
        result = DebateResult(
            symbol="AAPL",
            winner="bull",
            bull_score=100.0,
            bear_score=50.0,
            consensus_level=0.7,
            recommendation="buy",
            confidence=0.8,
        )

        assert result.symbol == "AAPL"
        assert result.winner == "bull"
        assert result.confidence == 0.8

    def test_result_to_dict(self):
        """Test converting result to dictionary."""
        result = DebateResult(
            symbol="AAPL",
            winner="bull",
            bull_score=100.0,
            bear_score=50.0,
            consensus_level=0.7,
            key_points=["Growth is strong"],
            disagreements=["Valuation debate"],
        )

        d = result.to_dict()
        assert d["symbol"] == "AAPL"
        assert d["winner"] == "bull"
        assert "timestamp" in d


class TestDebateIntegration:
    """Integration tests for full debate flow."""

    def test_full_debate_flow(self):
        """Test a complete multi-round debate."""
        config = DebateConfig(max_rounds=2, min_rounds=1)
        framework = DebateFramework(config)

        framework.start_debate("TSLA")

        # Round 1: Bull presents strong case
        round1 = framework.add_round()
        framework.submit_argument(
            agent_id="bull-1",
            argument_type=ArgumentType.BULLISH,
            claim="EV market leadership",
            evidence="50% market share",
            strength=ArgumentStrength.STRONG,
            target_factors=["market_share", "growth"],
        )

        # Bear rebuts
        bull_arg = round1.arguments[0]
        framework.submit_rebuttal(
            agent_id="bear-1",
            target_argument=bull_arg,
            counter_claim="Competition increasing",
            reasoning="Legacy automakers entering",
            effectiveness=0.6,
        )

        # Round 2: Bear presents case
        framework.add_round()
        framework.submit_argument(
            agent_id="bear-1",
            argument_type=ArgumentType.BEARISH,
            claim="Valuation too high",
            evidence="PE ratio 100x",
            strength=ArgumentStrength.MODERATE,
            target_factors=["valuation"],
        )

        result = framework.conclude_debate()

        assert result.rounds_completed == 2
        assert result.symbol == "TSLA"
        assert len(result.key_points) >= 0
        assert len(result.disagreements) >= 0
