"""DSPy signatures.

The model reasons in **math**, not graphs: it is given the start and target as
LaTeX (``start_latex`` / ``target_latex``) and emits a derivation. The semantic
graphs never reach the prompt — they are a code-side substrate (verification +
animation). ``module.forward`` derives the LaTeX from the context graphs via
``graph_to_latex`` and binds these fields. The docstring holds the expert's
*static* role and is what the optimizer (MIPROv2/GEPA) rewrites.
"""

from __future__ import annotations

import dspy

from .outputs import ProofTrajectory


class ProofCompletionSig(dspy.Signature):
    r"""Produce the math derivation that turns `start_latex` into `target_latex`.

    You are given a starting expression and a target expression, both as LaTeX.
    Emit a single trajectory of derivation `steps`. Each step is one mathematical
    move and holds the COMPLETE expression you reach after it, as LaTeX.

    Rules:
    - Each step has: `operation` (the move, e.g. "add 4 to both sides"),
      `expr_latex` (the COMPLETE, valid LaTeX of the expression after this move),
      and `justification` (why the move is mathematically valid).
    - In `operation` and `justification`, write ANY math as inline LaTeX delimited
      by `$…$` — e.g. "add $\frac{c}{a}$ to both sides", "the discriminant is
      $b^2 - 4ac$". Do NOT use backticks or bare text for math; plain words stay plain.
    - Every `expr_latex` MUST be a single, complete, parseable expression — one
      you could hand to a CAS. Never a partial or malformed fragment.
    - NEVER write `\pm` or `\mp` inside `expr_latex` — `x = \pm 3` is not a
      single expression. Emit the explicit disjunction (`x = 3 \lor x = -3`)
      or pick one branch as its own step with `change_type` = `solve`.
      (`\pm` is fine inside `operation`/`justification` prose.)
    - `expr_latex` is MATH ONLY: no `\text{…}` annotations, labels, or units
      tacked onto the expression — put commentary in `justification`.
    - Write EVERY multiplication explicitly with `\cdot`. A symbol written
      directly before a parenthesis is read as a FUNCTION CALL, not a product:
      `n(n+1)` means "apply function n to (n+1)" and is INVALID. Write
      `n \cdot (n+1)`, `r \cdot (\cos\theta + i\sin\theta)`, `2 \cdot (x+3)`.
      (Coefficient juxtaposition like `2x` or `a x^2` is fine; the hazard is a
      symbol immediately followed by `(`.)
    - Make each step small enough that its `expr_latex` is a clean intermediate
      expression. If a transformation is large, split it into as many smaller
      steps as needed. Prefer more small, valid steps over one big jump.
    - Each step also declares its `change_type` — the KIND of move it makes:
      `rewrite` (equivalence-preserving rearrangement: expand, factor, move a
      term across `=`), `solve` (narrows toward a solution: take a root, pick a
      branch, isolate the unknown), `substitute` (introduce a new variable,
      "let $u = …$"), `approximate` (the result is `\approx`, not exact), or
      `given` (a premise stated, not derived). A CAS verifies each step against
      its declared type, so label honestly: a step that picks one root of
      $x^2 = 4$ is `solve`, NOT `rewrite`.
    - The final step's `expr_latex` must equal `target_latex`.
    - Also give a short `title`: a few plain words naming what the derivation
      shows (e.g. "Completing the square", "Lorentz time dilation"). It is a
      human-readable display label, NOT a formula or a restatement of the target.
    - Give a one-sentence `goal` that states what this derivation establishes and
      why — the context a reader needs up front, BEFORE the steps (e.g. "Solve the
      general quadratic $ax^2+bx+c=0$ for $x$ to obtain the quadratic formula").
      Inline math in `$…$`. It is the framing, not a step.
    - Give `followups`: 2–4 short, self-contained prompts a learner could ask next
      to keep exploring this result with an AI tutor, BEYOND what these steps show
      (e.g. "Apply this to $2x^2+3x-5=0$", "When are the roots complex?", "Derive
      the vertex form"). Each is a question/instruction in plain words (inline math
      in `$…$` is fine), phrased so it stands alone as the next turn of a chat.
    - Give `prerequisites`: 1–4 short concepts/skills a learner should already know
      to follow this derivation (e.g. "completing the square", "the square root of
      both sides", "$\sqrt{x^2}=|x|$"). Concept names, not steps; inline math in `$…$`.
    """

    start_latex: str = dspy.InputField(desc="the starting expression, as LaTeX")
    target_latex: str = dspy.InputField(desc="the target expression to reach, as LaTeX")
    domain: str = dspy.InputField(desc="math domain hint (e.g. algebra, calculus), may be empty")
    intent: str = dspy.InputField(desc="what the derivation should accomplish, may be empty")
    lesson_context: str = dspy.InputField(desc="surrounding lesson summary, may be empty")
    instruction: str = dspy.InputField(desc="the user's request, may be empty")
    trajectory: ProofTrajectory = dspy.OutputField(
        desc="the ordered derivation steps, each a complete expression, from start to target"
    )
    title: str = dspy.OutputField(
        desc="a short, human-readable display title naming what this derivation shows "
             "(e.g. 'Completing the square') — plain words, NOT a formula"
    )
    goal: str = dspy.OutputField(
        desc="one sentence stating what the derivation establishes and why, to set "
             "context before the steps; inline math in $…$ (NOT a step, NOT the title)"
    )
    followups: list[str] = dspy.OutputField(
        desc="2-4 short, self-contained prompts to keep exploring this result with an "
             "AI tutor beyond the rendered steps; each stands alone as the next chat turn"
    )
    prerequisites: list[str] = dspy.OutputField(
        desc="1-4 short concepts/skills a learner should already know to follow this "
             "derivation (concept names, not steps); inline math in $…$"
    )
