"""
Skill: Financial Logic
=======================
Verify properties about portfolio composition, risk aggregation,
and position management.

This demonstrates how a client in finance would define their own
domain-specific rules and have the engine verify them.

Types:
  Amount   — reuses Nat (Z, S) for discrete units
  Portfolio — Empty | Position(asset, amount, rest)

Functions:
  total(Empty)                = Z
  total(Position(a, amt, r))  = add(amt, total(r))

  merge(Empty, p)                = p
  merge(Position(a, amt, r), p)  = Position(a, amt, merge(r, p))

  scale(Z, p)    = Empty
  scale(S(n), p) = merge(p, scale(n, p))
"""

from nexus_gate_pkg.engine.skills import Skill, TheoremDef, register_skill
from nexus_gate_pkg.engine.terms import Var, Const, App, RewriteRule, Equation

# Import Nat definitions we depend on
from nexus_gate_pkg.corpus.domain import DEFINITIONS as NAT_DEFS, Z, S, add


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

def Empty():
    return Const("Empty")

def Position(asset, amount, rest):
    return App("Position", [asset, amount, rest])

def total(p):
    return App("total", [p])

def merge(p1, p2):
    return App("merge", [p1, p2])

def risk(p):
    return App("risk", [p])


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

a, b = Var("a"), Var("b")
amt, amt2 = Var("amt"), Var("amt2")
p, q, r = Var("p"), Var("q"), Var("r")
n, m = Var("n"), Var("m")


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

FINANCE_DEFS = [
    # total: sum all position amounts
    RewriteRule("total_Empty", total(Empty()), Z()),
    RewriteRule("total_Position", total(Position(a, amt, r)),
                add(amt, total(r))),

    # merge: combine two portfolios
    RewriteRule("merge_Empty", merge(Empty(), p), p),
    RewriteRule("merge_Position", merge(Position(a, amt, r), p),
                Position(a, amt, merge(r, p))),

    # risk = total (simplified model: risk equals total exposure)
    RewriteRule("risk_def", risk(p), total(p)),
]


# ─── 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 ["finance"])

finance_skill = Skill(
    id="finance",
    name="Financial Logic",
    description="Verify portfolio composition, risk aggregation, and position rules",
    version="1.0.0",
    author="Example",
    depends_on=["core_math"],
    definitions=FINANCE_DEFS,
    theorems=[
        _thm("total_empty", "Empty portfolio has zero exposure",
             total(Empty()), Z(), diff="trivial"),

        _thm("merge_empty_right", "Merging with empty portfolio changes nothing",
             merge(p, Empty()), p,
             diff="easy", tags=["finance", "merge"]),

        _thm("total_merge", "Total exposure of merged portfolios equals sum of totals",
             total(merge(p, q)), add(total(p), total(q)),
             ctx=[Equation("add_assoc",
                 add(add(Var("a"), Var("b")), Var("c")),
                 add(Var("a"), add(Var("b"), Var("c"))))],
             diff="medium", tags=["finance", "merge", "total"]),

        _thm("risk_merge", "Risk of merged portfolios equals sum of risks",
             risk(merge(p, q)), add(risk(p), risk(q)),
             ctx=[
                 Equation("add_assoc",
                     add(add(Var("a"), Var("b")), Var("c")),
                     add(Var("a"), add(Var("b"), Var("c")))),
                 Equation("total_merge",
                     total(merge(Var("a"), Var("b"))),
                     add(total(Var("a")), total(Var("b")))),
             ],
             diff="medium", tags=["finance", "merge", "risk"]),

        _thm("merge_assoc", "Portfolio merging is associative",
             merge(merge(p, q), r), merge(p, merge(q, r)),
             diff="medium", tags=["finance", "merge", "algebra"]),
    ],
    vocabulary={
        "Empty": "empty portfolio",
        "Position": "position (asset, amount, rest)",
        "total": "total exposure",
        "merge": "combine portfolios",
        "risk": "risk exposure",
    },
    examples=[
        "Is merging portfolios associative?",
        "Does total exposure add up when I merge two portfolios?",
        "What's the risk of an empty portfolio?",
    ],
)

register_skill(finance_skill)

# Register induction scheme for Portfolio type
from nexus_gate_pkg.engine.proof import register_induction_scheme
register_induction_scheme(
    type_name="Portfolio",
    base_constructor="Empty",
    rec_constructor="Position",
    rec_arg_count=3,          # Position(asset, amount, rest)
    rec_positions=[2],        # only 'rest' (arg index 2) is recursive
    var_hints={"port", "portfolio"},
)
