"""Tests for auto-remediation feature.

Verifies that the remediation field is properly supported in the Finding
model, serialized in output formats, and displayed via --remediation flag.
"""

import ast
import json
import tempfile
from pathlib import Path

from mcpaudit.models import Finding, ScanResult, ScanSummary, Severity
from mcpaudit.formatters import format_text, format_json
from mcpaudit.rules.confused_deputy import ConfusedDeputyRule
from mcpaudit.rules.prompt_injection import PromptInjectionRule


class TestRemediationField:
    """Tests for the remediation field in Finding model."""

    def test_finding_has_remediation_field(self):
        f = Finding(
            rule_id="TEST-001",
            severity=Severity.HIGH,
            title="Test",
            description="Test finding",
            file="test.py",
            line=1,
            remediation="Replace open() with a sandboxed file reader.",
        )
        assert f.remediation == "Replace open() with a sandboxed file reader."

    def test_finding_remediation_default_empty(self):
        f = Finding(
            rule_id="TEST-001",
            severity=Severity.HIGH,
            title="Test",
            description="Test finding",
            file="test.py",
            line=1,
        )
        assert f.remediation == ""

    def test_remediation_in_to_dict_when_present(self):
        f = Finding(
            rule_id="TEST-001",
            severity=Severity.HIGH,
            title="Test",
            description="Test finding",
            file="test.py",
            line=1,
            remediation="Use parameterized queries.",
        )
        d = f.to_dict()
        assert "remediation" in d
        assert d["remediation"] == "Use parameterized queries."

    def test_remediation_not_in_to_dict_when_empty(self):
        f = Finding(
            rule_id="TEST-001",
            severity=Severity.HIGH,
            title="Test",
            description="Test finding",
            file="test.py",
            line=1,
        )
        d = f.to_dict()
        assert "remediation" not in d

    def test_remediation_in_json_output(self):
        result = ScanResult(
            file="test.py",
            findings=[
                Finding(
                    rule_id="TEST-001",
                    severity=Severity.HIGH,
                    title="Test",
                    description="Test",
                    file="test.py",
                    line=1,
                    remediation="Fix this issue.",
                ),
            ],
        )
        output = format_json([result])
        data = json.loads(output)
        finding = data["results"][0]["findings"][0]
        assert finding["remediation"] == "Fix this issue."


class TestRemediationInTextOutput:
    """Tests for remediation display in text formatter."""

    def _make_result(self, remediation: str = "") -> ScanResult:
        return ScanResult(
            file="test.py",
            findings=[
                Finding(
                    rule_id="TEST-001",
                    severity=Severity.HIGH,
                    title="Test Finding",
                    description="A test issue",
                    file="test.py",
                    line=5,
                    remediation=remediation,
                ),
            ],
        )

    def test_remediation_shown_when_flag_enabled(self):
        result = self._make_result("Use a safe alternative.")
        output = format_text([result], show_remediation=True)
        assert "Remediation:" in output
        assert "Use a safe alternative." in output

    def test_remediation_hidden_by_default(self):
        result = self._make_result("Use a safe alternative.")
        output = format_text([result])
        assert "Remediation:" not in output

    def test_no_remediation_line_when_empty(self):
        result = self._make_result("")
        output = format_text([result], show_remediation=True)
        assert "Remediation:" not in output


class TestRemediationInRules:
    """Tests that new rules produce remediation guidance."""

    def test_confused_deputy_provides_remediation(self):
        code = '''
def handle_tool_read(path):
    return open(path).read()
'''
        tree = ast.parse(code)
        rule = ConfusedDeputyRule()
        findings = rule.check(tree, code)
        assert len(findings) >= 1
        assert findings[0].remediation != ""

    def test_prompt_injection_provides_remediation(self):
        code = '''
@server.tool(description=f"Handle {action}")
def handle(data):
    return data
'''
        tree = ast.parse(code)
        rule = PromptInjectionRule()
        findings = rule.check(tree, code)
        assert len(findings) >= 1
        assert findings[0].remediation != ""


class TestCLIRemediationFlag:
    """Tests for --remediation CLI flag."""

    def test_remediation_flag_shows_guidance(self, tmp_path, capsys):
        f = tmp_path / "test.py"
        f.write_text('''
def handle_tool_read(path):
    return open(path).read()
''')
        from mcpaudit.__main__ import main
        main([str(f), "--remediation"])
        captured = capsys.readouterr()
        assert "Remediation:" in captured.out

    def test_no_remediation_flag_hides_guidance(self, tmp_path, capsys):
        f = tmp_path / "test.py"
        f.write_text('''
def handle_tool_read(path):
    return open(path).read()
''')
        from mcpaudit.__main__ import main
        main([str(f)])
        captured = capsys.readouterr()
        assert "Remediation:" not in captured.out
