from __future__ import annotations

import unittest

from src.permissions import ToolPermissionContext


class TestToolPermissionContext(unittest.TestCase):
    # 1. Empty context blocks nothing
    def test_empty_context_blocks_nothing(self) -> None:
        ctx = ToolPermissionContext()
        self.assertFalse(ctx.blocks("anything"))
        self.assertFalse(ctx.blocks(""))

    # 2. Exact name blocking (case insensitive)
    def test_exact_name_blocking(self) -> None:
        ctx = ToolPermissionContext.from_iterables(deny_names=["dangerous_tool"])
        self.assertTrue(ctx.blocks("dangerous_tool"))
        self.assertTrue(ctx.blocks("Dangerous_Tool"))
        self.assertTrue(ctx.blocks("DANGEROUS_TOOL"))
        self.assertFalse(ctx.blocks("safe_tool"))

    # 3. Prefix blocking (case insensitive)
    def test_prefix_blocking(self) -> None:
        ctx = ToolPermissionContext.from_iterables(deny_prefixes=["admin_"])
        self.assertTrue(ctx.blocks("admin_delete"))
        self.assertTrue(ctx.blocks("Admin_Delete"))
        self.assertTrue(ctx.blocks("ADMIN_CREATE"))
        self.assertFalse(ctx.blocks("user_admin"))

    # 4. Combined name + prefix blocking
    def test_combined_name_and_prefix_blocking(self) -> None:
        ctx = ToolPermissionContext.from_iterables(
            deny_names=["rm"],
            deny_prefixes=["sudo_"],
        )
        self.assertTrue(ctx.blocks("rm"))
        self.assertTrue(ctx.blocks("sudo_restart"))
        self.assertFalse(ctx.blocks("ls"))

    # 5. Non-matching names are allowed
    def test_non_matching_names_allowed(self) -> None:
        ctx = ToolPermissionContext.from_iterables(
            deny_names=["blocked"],
            deny_prefixes=["bad_"],
        )
        self.assertFalse(ctx.blocks("allowed"))
        self.assertFalse(ctx.blocks("good_tool"))
        self.assertFalse(ctx.blocks("not_bad"))

    # 6. from_iterables with None args
    def test_from_iterables_none_args(self) -> None:
        ctx = ToolPermissionContext.from_iterables(deny_names=None, deny_prefixes=None)
        self.assertEqual(ctx.deny_names, frozenset())
        self.assertEqual(ctx.deny_prefixes, ())
        self.assertFalse(ctx.blocks("anything"))

    def test_from_iterables_default_args(self) -> None:
        ctx = ToolPermissionContext.from_iterables()
        self.assertEqual(ctx.deny_names, frozenset())
        self.assertEqual(ctx.deny_prefixes, ())

    # 7. from_iterables normalizes to lowercase
    def test_from_iterables_normalizes_to_lowercase(self) -> None:
        ctx = ToolPermissionContext.from_iterables(
            deny_names=["FooBar"],
            deny_prefixes=["PFX_"],
        )
        self.assertIn("foobar", ctx.deny_names)
        self.assertNotIn("FooBar", ctx.deny_names)
        self.assertEqual(ctx.deny_prefixes, ("pfx_",))
        self.assertTrue(ctx.blocks("FOOBAR"))
        self.assertTrue(ctx.blocks("pfx_something"))

    # 8. Multiple deny_names
    def test_multiple_deny_names(self) -> None:
        ctx = ToolPermissionContext.from_iterables(
            deny_names=["tool_a", "tool_b", "tool_c"],
        )
        self.assertTrue(ctx.blocks("tool_a"))
        self.assertTrue(ctx.blocks("tool_b"))
        self.assertTrue(ctx.blocks("tool_c"))
        self.assertFalse(ctx.blocks("tool_d"))


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