"""tests/test_atelier_mcp.py — REQ-225.

Covers: tool registration (all 4 tools discoverable), lookup_principle
returns the principle text + core C-rule, validate_against_principles
catches a planted C1 (correctness) + C7 (observability) violation in a
known-bad snippet and passes a known-good snippet, matrix_lookup returns
the domain→core mapping, plugin discovery loads all plugins in plugins/.
"""
import os
import sys
import unittest

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from mcp.atelier.server import NovaAtelierServer


class TestPluginDiscovery(unittest.TestCase):
    def setUp(self):
        self.server = NovaAtelierServer()
        self.loaded = self.server.load_plugins()

    def test_both_plugins_loaded(self):
        self.assertIn("principles", self.loaded)
        self.assertIn("validation", self.loaded)

    def test_four_tools_registered(self):
        tools = self.server.list_tools()
        names = {t["name"] for t in tools}
        self.assertIn("atelier_lookup_principle", names)
        self.assertIn("atelier_list_domains", names)
        self.assertIn("atelier_matrix_lookup", names)
        self.assertIn("atelier_validate_against_principles", names)
        self.assertEqual(len(names), 4)


class TestLookupPrinciple(unittest.TestCase):
    def setUp(self):
        self.server = NovaAtelierServer()
        self.server.load_plugins()

    def test_lookup_security_p4(self):
        result = self.server.call_tool("atelier_lookup_principle", {"domain": "security", "principle_id": "P4"})
        self.assertNotIn("error", result)
        self.assertEqual(result["domain"], "security")
        self.assertEqual(result["principle_id"], "P4")
        self.assertIn("Secrets", result["title"])
        self.assertIn("C1", result["core_c_rule"])
        self.assertIn("C7", result["core_c_rule"])

    def test_lookup_security_p1(self):
        result = self.server.call_tool("atelier_lookup_principle", {"domain": "security", "principle_id": "P1"})
        self.assertNotIn("error", result)
        self.assertIn("Boundary", result["title"])

    def test_lookup_unknown_domain(self):
        result = self.server.call_tool("atelier_lookup_principle", {"domain": "nonexistent", "principle_id": "P1"})
        self.assertIn("error", result)

    def test_lookup_unknown_principle(self):
        result = self.server.call_tool("atelier_lookup_principle", {"domain": "security", "principle_id": "P99"})
        self.assertIn("error", result)


class TestListDomains(unittest.TestCase):
    def setUp(self):
        self.server = NovaAtelierServer()
        self.server.load_plugins()

    def test_returns_19_domains(self):
        result = self.server.call_tool("atelier_list_domains", {})
        self.assertEqual(len(result), 19)

    def test_security_is_nova_relevant(self):
        result = self.server.call_tool("atelier_list_domains", {})
        sec = next(d for d in result if d["domain"] == "security")
        self.assertTrue(sec["nova_relevant"])

    def test_ui_ux_not_nova_relevant(self):
        result = self.server.call_tool("atelier_list_domains", {})
        ui = next(d for d in result if d["domain"] == "ui-ux")
        self.assertFalse(ui["nova_relevant"])


class TestMatrixLookup(unittest.TestCase):
    def setUp(self):
        self.server = NovaAtelierServer()
        self.server.load_plugins()

    def test_security_matrix(self):
        result = self.server.call_tool("atelier_matrix_lookup", {"domain": "security"})
        self.assertEqual(result["domain"], "security")
        self.assertEqual(len(result["mapping"]), 10)
        p4 = next(m for m in result["mapping"] if m["p"] == "P4")
        self.assertIn("C1", p4["core"])
        self.assertIn("C7", p4["core"])

    def test_unknown_domain_matrix(self):
        result = self.server.call_tool("atelier_matrix_lookup", {"domain": "nonexistent"})
        self.assertEqual(result["mapping"], [])


class TestValidateAgainstPrinciples(unittest.TestCase):
    def setUp(self):
        self.server = NovaAtelierServer()
        self.server.load_plugins()

    def test_good_snippet_passes(self):
        good = """
import logging
logger = logging.getLogger(__name__)

def get_customer(customer_id, request_id):
    if not customer_id:
        raise ValueError("customer_id required")
    logger.info("fetching customer %s (request %s)", customer_id, request_id)
    return db.query(customer_id)
"""
        result = self.server.call_tool("atelier_validate_against_principles", {"snippet": good})
        # Should not have FAIL on secrets (no hardcoded secrets)
        sec_checks = [r for r in result["results"] if r["check_id"].startswith("SEC.1")]
        for c in sec_checks:
            self.assertEqual(c["status"], "PASS", f"SEC.1 should PASS: {c}")

    def test_bad_snippet_catches_secret(self):
        bad = """
api_key = "sk-1234567890abcdef"

def get_data():
    pass
"""
        result = self.server.call_tool("atelier_validate_against_principles", {"snippet": bad})
        # SEC.1 (secrets in code) should FAIL
        sec1 = next(r for r in result["results"] if r["check_id"] == "SEC.1")
        self.assertEqual(sec1["status"], "FAIL")

    def test_bad_snippet_catches_swallowed_error(self):
        bad = """
try:
    do_something()
except:
    pass
"""
        result = self.server.call_tool("atelier_validate_against_principles", {"snippet": bad})
        # C1.2 (handles failure cases) should FAIL because of `except: pass`
        c12 = next(r for r in result["results"] if r["check_id"] == "C1.2")
        self.assertEqual(c12["status"], "FAIL")

    def test_bad_snippet_catches_obfuscated_names(self):
        bad = """
def doStuff(data, temp, x):
    return data + temp + x
"""
        result = self.server.call_tool("atelier_validate_against_principles", {"snippet": bad})
        # C2.1 (names intent-revealing) should FAIL
        c21 = next(r for r in result["results"] if r["check_id"] == "C2.1")
        self.assertEqual(c21["status"], "FAIL")

    def test_result_structure(self):
        result = self.server.call_tool("atelier_validate_against_principles", {"snippet": "x = 1"})
        self.assertIn("overall", result)
        self.assertIn("results", result)
        self.assertIsInstance(result["results"], list)
        self.assertGreater(len(result["results"]), 0)


if __name__ == "__main__":
    unittest.main()