"""REQ-107: route_halt_artifact is a real implementation (SNS + outbox fallback)."""
import json
import os
import sys
from pathlib import Path
from unittest import mock

import pytest

ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT))

from core.separation_of_duties import route_halt_artifact


def test_route_halt_publishes_to_sns_when_arn_set(monkeypatch):
    """With ACDL_SOD_HALT_TOPIC_ARN set, the SNS client receives the publish."""
    monkeypatch.setenv("ACDL_SOD_HALT_TOPIC_ARN", "arn:aws:sns:us-east-1:000000000000:acdl-sod-halt")
    sns_client = mock.MagicMock()
    route_halt_artifact("contract-123", "SEPARATION_OF_DUTIES_VIOLATION: x==y",
                        oncall_client=sns_client)
    sns_client.publish.assert_called_once()
    call = sns_client.publish.call_args
    assert call.kwargs["TopicArn"] == "arn:aws:sns:us-east-1:000000000000:acdl-sod-halt"
    assert "contract-123" in call.kwargs["Message"]
    assert "SEPARATION_OF_DUTIES_VIOLATION" in call.kwargs["Message"]
    assert call.kwargs["Subject"] == "ACDL SoD halt"


def test_route_halt_falls_back_to_stderr_when_arn_unset(monkeypatch, capsys):
    """Without ACDL_SOD_HALT_TOPIC_ARN, a stderr emission occurs."""
    monkeypatch.delenv("ACDL_SOD_HALT_TOPIC_ARN", raising=False)
    # Mock outbox_writer.write_event to avoid AWS calls.
    with mock.patch("core.outbox_writer.write_event", return_value=None):
        route_halt_artifact("contract-456", "violation", oncall_client=None)
    captured = capsys.readouterr()
    assert "contract-456" in captured.err
    assert "violation" in captured.err


def test_route_halt_outbox_fallback_writes_event(monkeypatch):
    """Without the SNS ARN, the outbox fallback writes a SEPARATION_OF_DUTIES_VIOLATION event."""
    monkeypatch.delenv("ACDL_SOD_HALT_TOPIC_ARN", raising=False)
    with mock.patch("core.outbox_writer.write_event") as mock_write:
        route_halt_artifact("contract-789", "sod violation", oncall_client=None)
        mock_write.assert_called_once()
        event = mock_write.call_args[0][0]
        assert event["contractId"] == "contract-789"
        assert event["eventType"] == "SEPARATION_OF_DUTIES_VIOLATION"
        assert "sod violation" in event["reason"]


def test_route_halt_sns_failure_falls_back_to_outbox(monkeypatch):
    """If SNS publish raises, the outbox fallback is used."""
    monkeypatch.setenv("ACDL_SOD_HALT_TOPIC_ARN", "arn:aws:sns:us-east-1:000000000000:acdl-sod-halt")
    sns_client = mock.MagicMock()
    sns_client.publish.side_effect = Exception("SNS down")
    with mock.patch("core.outbox_writer.write_event") as mock_write:
        route_halt_artifact("contract-fail", "violation", oncall_client=sns_client)
        mock_write.assert_called_once()


def test_sns_topic_defined_in_terraform():
    """terraform/platform/main.tf defines the acdl-sod-halt SNS topic."""
    tf = (ROOT / "terraform" / "platform" / "main.tf").read_text()
    assert "aws_sns_topic" in tf
    assert "acdl-sod-halt" in tf
    assert "acdl_sod_halt_topic_arn" in tf