"""
tests/test_release_check_platform_review.py

Tests for platform_review_required release gate:
  - warn mode: always pass=True + recommendations when score >= warn_at
  - strict mode: should_fail=True when score >= fail_at
  - skipped gracefully when no service_name
  - non-fatal on errors
"""
import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../services/router"))

import asyncio
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from release_check_runner import _run_platform_review_required


def _make_tool_manager(pressure_score: int, band: str,
                       requires_review: bool = False,
                       signals_summary=None,
                       fail: bool = False) -> MagicMock:
    tm = MagicMock()
    if fail:
        result = MagicMock(success=False, result=None, error="test error")
    else:
        result = MagicMock(
            success=True,
            result={
                "score": pressure_score,
                "band": band,
                "requires_arch_review": requires_review,
                "signals_summary": signals_summary or [],
                "components": {},
            },
        )
    tm.execute_tool = AsyncMock(return_value=result)
    return tm


class TestPlatformReviewRequiredGate:
    def test_warn_mode_pass_below_threshold(self):
        """Score below warn_at → pass, no recommendations, no failure."""
        tm = _make_tool_manager(30, "medium")
        ok, gate = asyncio.run(
            _run_platform_review_required(tm, "agent_ops", "gateway", "prod")
        )
        assert ok is True
        assert gate["name"] == "platform_review_required"
        assert gate.get("skipped") is False
        assert gate.get("should_fail") is False
        assert gate.get("recommendations", []) == []

    def test_warn_mode_adds_recommendation_above_warn_at(self):
        """Score >= warn_at → pass=True but recommendation added."""
        tm = _make_tool_manager(
            65, "high",
            signals_summary=["High recurrence in 30d"]
        )
        ok, gate = asyncio.run(
            _run_platform_review_required(tm, "agent_ops", "router", "prod")
        )
        assert ok is True
        assert len(gate.get("recommendations", [])) >= 1
        assert gate.get("should_fail") is False

    def test_fail_at_sets_should_fail_true(self):
        """Score >= fail_at → should_fail=True (gate decides blocking in strict mode)."""
        tm = _make_tool_manager(90, "critical", requires_review=True)
        ok, gate = asyncio.run(
            _run_platform_review_required(tm, "agent_ops", "gateway", "prod")
        )
        assert ok is True
        assert gate.get("should_fail") is True
        # Always pass=True in warn mode (caller handles strict)

    def test_arch_review_required_adds_recommendation(self):
        """When requires_arch_review=True, an extra recommendation is added."""
        tm = _make_tool_manager(65, "high", requires_review=True)
        _, gate = asyncio.run(
            _run_platform_review_required(tm, "agent_ops", "svc", "prod")
        )
        recs = gate.get("recommendations", [])
        assert any("Architecture review" in r or "architecture" in r.lower() for r in recs)

    def test_skipped_when_no_service_name(self):
        """Gate skips gracefully when no service_name provided."""
        tm = _make_tool_manager(0, "low")
        ok, gate = asyncio.run(
            _run_platform_review_required(tm, "agent_ops", service_name="")
        )
        assert ok is True
        assert gate.get("skipped") is True

    def test_non_fatal_on_tool_error(self):
        """Tool failure → skip (never block release)."""
        tm = _make_tool_manager(0, "low", fail=True)
        ok, gate = asyncio.run(
            _run_platform_review_required(tm, "agent_ops", "svc", "prod")
        )
        assert ok is True
        assert gate.get("skipped") is True

    def test_non_fatal_on_exception(self):
        """Any exception in gate → skip."""
        tm = MagicMock()
        tm.execute_tool = AsyncMock(side_effect=RuntimeError("unexpected"))
        ok, gate = asyncio.run(
            _run_platform_review_required(tm, "agent_ops", "svc", "prod")
        )
        assert ok is True
        assert gate.get("skipped") is True

    def test_gate_includes_score_and_band(self):
        tm = _make_tool_manager(55, "high")
        _, gate = asyncio.run(
            _run_platform_review_required(tm, "agent_ops", "svc", "prod")
        )
        assert gate.get("score") == 55
        assert gate.get("band") == "high"

    def test_gate_includes_warn_fail_thresholds(self):
        tm = _make_tool_manager(50, "medium")
        _, gate = asyncio.run(
            _run_platform_review_required(tm, "agent_ops", "svc", "prod")
        )
        assert "warn_at" in gate
        assert "fail_at" in gate

    def test_score_below_fail_at_should_fail_false(self):
        tm = _make_tool_manager(75, "critical", requires_review=True)
        _, gate = asyncio.run(
            _run_platform_review_required(tm, "agent_ops", "svc", "prod")
        )
        # 75 < fail_at (85) → should_fail = False
        assert gate.get("should_fail") is False

    def test_score_exactly_at_fail_at_should_fail_true(self):
        tm = _make_tool_manager(85, "critical", requires_review=True)
        _, gate = asyncio.run(
            _run_platform_review_required(tm, "agent_ops", "svc", "prod")
        )
        assert gate.get("should_fail") is True

    def test_note_includes_score(self):
        tm = _make_tool_manager(60, "high")
        _, gate = asyncio.run(
            _run_platform_review_required(tm, "agent_ops", "svc", "prod")
        )
        assert "60" in gate.get("note", "")
