"""End-to-end feedback and calibration tests — requires a running FalkorDB."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

from koan.graph import (
    ConfidenceCalibrator,
    DecisionTracer,
    FeedbackType,
    GraphConfig,
    create_graph_client,
    record_feedback,
)

if TYPE_CHECKING:
    from collections.abc import AsyncIterator

    from koan.graph.client import GraphClient

pytestmark = [pytest.mark.integration, pytest.mark.graph]


@pytest.fixture
async def falkor_client() -> AsyncIterator[GraphClient]:
    config = GraphConfig(
        provider="falkordb",
        uri="redis://localhost:6379",
        database="koan_feedback_e2e_test",
    )
    async with create_graph_client(config) as client:
        yield client


class TestFeedbackE2E:
    async def test_record_and_query_feedback(self, falkor_client: GraphClient) -> None:
        """Record a run, attach feedback, then query it via calibrator."""
        run_id = "e2e-fb-run-001"

        # 1. Create a run with a decision and outcome
        async with DecisionTracer(
            falkor_client,
            run_id=run_id,
            agent_id="e2e-fb-agent",
            thread_id="e2e-fb-thread",
        ) as tracer:
            decision_id = await tracer.record_decision(
                description="Test decision for feedback",
                decision_type="classification",
                confidence=0.9,
                reasoning="Test reasoning",
            )
            await tracer.record_outcome(
                status="success",
                result="Test result",
            )

        # 2. Record positive feedback
        fid1 = await record_feedback(
            falkor_client,
            run_id=run_id,
            feedback_type=FeedbackType.THUMBS_UP,
            score=1.0,
            comment="Great response!",
        )
        assert fid1

        # 3. Record a fork signal
        fid2 = await record_feedback(
            falkor_client,
            run_id=run_id,
            feedback_type=FeedbackType.FORK,
            score=-0.5,
        )
        assert fid2

        # 4. Query feedback via calibrator
        calibrator = ConfidenceCalibrator(falkor_client)
        cal = await calibrator.get_calibration(agent_id="e2e-fb-agent")

        assert cal.sample_count >= 2
        assert cal.factor <= 1.0
        assert cal.factor >= 0.3

    async def test_feedback_summary(self, falkor_client: GraphClient) -> None:
        """Verify feedback summary returns meaningful data."""
        run_id = "e2e-fb-run-002"

        async with DecisionTracer(
            falkor_client,
            run_id=run_id,
            agent_id="e2e-fb-agent-2",
            thread_id="e2e-fb-thread-2",
        ) as tracer:
            await tracer.record_decision(
                description="Another test decision",
                decision_type="routing",
                confidence=0.8,
                reasoning="Test",
            )
            await tracer.record_outcome(status="success", result="Done")

        await record_feedback(
            falkor_client,
            run_id=run_id,
            feedback_type=FeedbackType.EXPLICIT,
            score=0.8,
            comment="Mostly helpful",
        )

        calibrator = ConfidenceCalibrator(falkor_client)
        summary = await calibrator.get_feedback_summary(agent_id="e2e-fb-agent-2")

        assert summary.get("total_feedback", 0) >= 1
        assert "Mostly helpful" in summary.get("recent_comments", [])

    async def test_calibration_with_decision_type_filter(self, falkor_client: GraphClient) -> None:
        """Calibration filtered by decision_type only counts matching feedback."""
        run_id = "e2e-fb-run-003"

        async with DecisionTracer(
            falkor_client,
            run_id=run_id,
            agent_id="e2e-fb-agent-3",
            thread_id="e2e-fb-thread-3",
        ) as tracer:
            await tracer.record_decision(
                description="Routing decision",
                decision_type="routing",
                confidence=0.7,
                reasoning="Routed to team A",
            )
            await tracer.record_outcome(status="success", result="Routed")

        await record_feedback(
            falkor_client,
            run_id=run_id,
            feedback_type=FeedbackType.THUMBS_DOWN,
            score=-1.0,
            comment="Wrong team",
        )

        calibrator = ConfidenceCalibrator(falkor_client)
        cal = await calibrator.get_calibration(
            agent_id="e2e-fb-agent-3",
            decision_type="routing",
        )
        assert cal.sample_count >= 1
        assert cal.negative_rate > 0
