"""
Skill: Cybersecurity
=====================
Verify firewall rule composition, access policies, and threat assessment logic.

Real-world use cases:
  - "Prove that merging two firewall rulesets preserves all deny rules"
  - "Verify that combining two security zones doesn't escalate privileges"
  - "Show that threat severity aggregation is consistent"

Types:
  RuleSet  — NoRules | Rule(action, priority, rest)
  ThreatLevel — uses Nat (0=none, 1=low, 2=medium, ...)

Functions:
  rule_count(NoRules)         = Z
  rule_count(Rule(a,p,rest))  = S(rule_count(rest))

  merge_rules(NoRules, rs)        = rs
  merge_rules(Rule(a,p,rest), rs) = Rule(a, p, merge_rules(rest, rs))

  max_priority(NoRules)           = Z
  max_priority(Rule(a,p,rest))    = max(p, max_priority(rest))
"""

from nexus_gate_pkg.engine.skills import Skill, TheoremDef, register_skill
from nexus_gate_pkg.engine.terms import Var, Const, App, RewriteRule, Equation
from nexus_gate_pkg.engine.proof import register_induction_scheme
from nexus_gate_pkg.corpus.domain import Z, S, add


# ─── Constructors ────────────────────────────────────────

def NoRules():
    return Const("NoRules")

def Rule(action, priority, rest):
    return App("Rule", [action, priority, rest])

def rule_count(rs):
    return App("rule_count", [rs])

def merge_rules(rs1, rs2):
    return App("merge_rules", [rs1, rs2])


# ─── Variables ───────────────────────────────────────────

rs, rs2, rs3 = Var("rs"), Var("rs2"), Var("rs3")
a, p, r = Var("a"), Var("p"), Var("r")


# ─── Definitions ─────────────────────────────────────────

CYBER_DEFS = [
    RewriteRule("rule_count_empty", rule_count(NoRules()), Z()),
    RewriteRule("rule_count_rule", rule_count(Rule(a, p, r)),
                S(rule_count(r))),

    RewriteRule("merge_rules_empty", merge_rules(NoRules(), rs), rs),
    RewriteRule("merge_rules_rule", merge_rules(Rule(a, p, r), rs),
                Rule(a, p, merge_rules(r, rs))),
]


# ─── Theorems ────────────────────────────────────────────

def _thm(name, desc, lhs, rhs, ctx=None, diff="medium", tags=None):
    return TheoremDef(name, desc, lhs, rhs, context=ctx or [],
                      difficulty=diff, tags=tags or ["cyber"])

cyber_skill = Skill(
    id="cyber",
    name="Cybersecurity",
    description="Verify firewall rules, access policies, and security logic",
    version="1.0.0",
    definitions=CYBER_DEFS,
    theorems=[
        _thm("empty_ruleset_safe",
             "An empty firewall has zero rules (clean baseline)",
             rule_count(NoRules()), Z(),
             diff="trivial"),

        _thm("merge_preserves_count",
             "Merging two firewalls preserves the total number of rules — nothing silently dropped",
             rule_count(merge_rules(rs, rs2)),
             add(rule_count(rs), rule_count(rs2)),
             diff="medium"),

        _thm("merge_empty_is_identity",
             "Merging with an empty ruleset changes nothing — safe no-op",
             merge_rules(rs, NoRules()), rs,
             diff="easy"),

        _thm("merge_is_associative",
             "Order of merging three firewalls doesn't matter — consistent composition",
             merge_rules(merge_rules(rs, rs2), rs3),
             merge_rules(rs, merge_rules(rs2, rs3)),
             diff="medium"),
    ],
    vocabulary={
        "NoRules": "empty firewall",
        "Rule": "firewall rule (action, priority, rest)",
        "rule_count": "total rule count",
        "merge_rules": "merge firewalls",
    },
    examples=[
        "Are any rules lost when I merge two firewalls?",
        "Is merging firewalls order-independent?",
        "Is an empty ruleset actually empty?",
    ],
)

register_skill(cyber_skill)

register_induction_scheme(
    type_name="RuleSet",
    base_constructor="NoRules",
    rec_constructor="Rule",
    rec_arg_count=3,        # Rule(action, priority, rest)
    rec_positions=[2],      # 'rest' is recursive
    var_hints={"rs", "rs2", "rs3", "rules", "fw", "firewall"},
)
