"""
lambdagent Hello World

从最简单开始，逐步展示 11 个 Lambda 构造。
每一步都标注 Lambda 演算对应。

用法:
    export ANTHROPIC_API_KEY=sk-...
    python hello.py
"""

import sys, os
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from lambdagent import (
    Lam, Tool, Compose, If, Loop, Pair, Fst, Snd,
    Route, Guard, Context, Dataset,
)
from lambdagent.extensions import Memory


def main():
    ctx = Context()

    # ════════════════════════════════════════════
    # 1. Lam — λ 抽象
    #    λx. LLM(x)
    # ════════════════════════════════════════════
    print("─── 1. Lam (λ abstraction) ───")

    hello = Lam(
        "hello",
        "You are a friendly assistant. Reply in one short sentence.",
        max_tokens=64,
    )
    print(f"  λ> {hello('Hello!', ctx)}")
    print()

    # ════════════════════════════════════════════
    # 2. Tool — 原语 / Oracle
    #    λx. f(x)  where f is a Python function
    # ════════════════════════════════════════════
    print("─── 2. Tool (primitive) ───")

    shout = Tool("shout", lambda x: str(x).upper() + "!!!")
    print(f"  λ> {shout('hello world', ctx)}")
    print()

    # ════════════════════════════════════════════
    # 3. Compose — 函数组合
    #    f >> g = λx. g(f(x))
    # ════════════════════════════════════════════
    print("─── 3. Compose (f >> g) ───")

    pipeline = hello >> shout   # 先让 LLM 回复，再全大写
    print(f"  λ> {pipeline('Hi there', ctx)}")
    print()

    # ════════════════════════════════════════════
    # 4. Dataset → Lam — 数据集变函数
    #    D.to_lam() = λx. LLM_{prompt=encode(D)}(x)
    # ════════════════════════════════════════════
    print("─── 4. Dataset → Lam ───")

    succ = Dataset(
        examples=[("0","1"), ("1","2"), ("2","3"), ("9","10")],
        description="Given n, output n+1. Output ONLY the number.",
    ).to_lam("SUCC")

    print(f"  SUCC(41) = {succ('41', ctx)}")
    print(f"  SUCC(99) = {succ('99', ctx)}")
    print()

    # ════════════════════════════════════════════
    # 5. Pair / Fst / Snd — Church 对
    #    PAIR = λa.λb.λf. f a b
    # ════════════════════════════════════════════
    print("─── 5. Pair / Fst / Snd ───")

    both = Pair(hello, shout)
    result = both("Hey", ctx)
    print(f"  Pair result: {result}")
    print(f"  Fst: {Fst()('(a, b) tuple test: ' + str(result), ctx) if False else result[0]}")
    print(f"  Snd: {result[1]}")
    print()

    # ════════════════════════════════════════════
    # 6. If — Church 条件
    #    IF c t e = c t e
    # ════════════════════════════════════════════
    print("─── 6. If (Church boolean) ───")

    branch = If(
        cond=lambda x: int(x) > 10,
        then_=Tool("big", lambda x: f"{x} is BIG"),
        else_=Tool("small", lambda x: f"{x} is small"),
    )
    print(f"  If(5 > 10):  {branch('5', ctx)}")
    print(f"  If(42 > 10): {branch('42', ctx)}")
    print()

    # ════════════════════════════════════════════
    # 7. Loop — Y 组合子
    #    Y(λself.λx. if done then x else self(body(x)))
    # ════════════════════════════════════════════
    print("─── 7. Loop (Y combinator) ───")

    counter = Tool("inc", lambda x: str(int(x) + 1))
    loop = Loop(
        body=counter,
        condition=lambda result, step: int(result) >= 5,
        max_steps=20,
    )
    print(f"  Y(inc)(0) until ≥5: {loop('0', ctx)}")
    print()

    # ════════════════════════════════════════════
    # 8. Route — 广义 Church 布尔 (CASE)
    #    CASE classifier(x) [(l₁,a₁), (l₂,a₂), ...]
    # ════════════════════════════════════════════
    print("─── 8. Route (CASE) ───")

    classifier = Lam(
        "classify",
        "Classify the input as exactly one word: 'math' or 'greeting'. Output ONLY that word.",
        max_tokens=8,
    )
    router = Route(
        classifier=classifier,
        routes={
            "math": Tool("math_handler", lambda x: f"[MATH] {x}"),
            "greeting": Tool("greet_handler", lambda x: f"[GREET] Hello! {x}"),
        },
        default=Tool("default", lambda x: f"[DEFAULT] {x}"),
    )
    print(f"  Route('2+2'):  {router('2+2', ctx)}")
    print(f"  Route('Hi!'):  {router('Hi!', ctx)}")
    print()

    # ════════════════════════════════════════════
    # 9. Guard — 依赖类型 {x:T | P(x)}
    #    if P(result) then result else retry
    # ════════════════════════════════════════════
    print("─── 9. Guard (dependent type) ───")

    strict_num = Guard(
        agent=succ,
        validator=lambda x: str(x).strip().isdigit(),
        retry=2,
    )
    print(f"  Guard(SUCC(7)): {strict_num('7', ctx)}")
    print()

    # ════════════════════════════════════════════
    # 10. Memory — 环境扩展 Γ' = Γ ∪ store
    # ════════════════════════════════════════════
    print("─── 10. Memory (Γ extension) ───")

    greeter = Lam(
        "greeter",
        "Greet the user. If you know their name from memory, use it. One sentence.",
        max_tokens=64,
    )
    stateful = Memory(greeter, store={"user_name": "Alice", "mood": "happy"})
    print(f"  Memory(greeter): {stateful('Hello!', ctx)}")
    print()

    # ════════════════════════════════════════════
    # 11. 组合: 完整 Agent pipeline
    #     extract >> Pair(analyze, critique) >> synthesize >> Loop(refine)
    # ════════════════════════════════════════════
    print("─── 11. Full pipeline ───")

    extract = Lam("extract", "Extract the key claim from this text. One sentence.", max_tokens=64)
    analyze = Lam("analyze", "Is this claim true or false? One sentence.", max_tokens=64)
    combine = Tool("combine", lambda pair: f"Claim: {pair[0]}\nAnalysis: {pair[1]}")

    full = extract >> Pair(analyze, shout) >> combine
    result = full("The Earth orbits the Sun in approximately 365 days.", ctx)
    print(f"  {result}")
    print()

    # ════════════════════════════════════════════
    # β-规约追踪
    # ════════════════════════════════════════════
    print("─── β-reduction trace ───")
    ctx.print_trace()
    print(f"\nTotal: {len(ctx.trace)} β-reductions")


if __name__ == "__main__":
    main()
