"""Trading mathematics: deterministic, self-contained Manim Community scenes.
All examples exclude costs unless explicitly stated. Four 24-second beats.
Teal = long/gain, coral = short/loss, gold = reference or collateral threshold.
"""
from manim import *
from math import erf, exp, log, sqrt

BG = "#0b1524"
INK = "#e7eef7"
TEAL = "#41dbc0"
CORAL = "#ff907e"
GOLD = "#f6c453"
BLUE = "#65aaff"

def text(value, size=32, color=INK):
    return Text(value, font="DejaVu Sans", font_size=size, color=color)

def beat(scene, title, caption):
    scene.clear()
    scene.camera.background_color = BG
    scene.beat_start = scene.time
    heading = text(title, 36).move_to([0, 3.25, 0])
    if heading.width > 12:
        heading.scale_to_fit_width(12)
    footer = text(caption, 23).move_to([0, -3.3, 0])
    if footer.width > 12:
        footer.scale_to_fit_width(12)
    scene.add(heading, footer)

def end(scene):
    scene.wait(max(0.1, 24 - (scene.time - scene.beat_start)))

def axes(xr, yr, xlabel, ylabel):
    a = Axes(x_range=xr, y_range=yr, x_length=10, y_length=4.1,
             tips=False, axis_config={"color": "#66778e", "include_ticks": True})
    a.move_to([0, -0.25, 0])
    labels = VGroup(text(xlabel, 23).move_to([0, -2.85, 0]),
                    text(ylabel, 23).move_to([-4.3, 2.1, 0]))
    # Numeric scales make the plotted claims independently checkable.
    for value in range(int(xr[0]), int(xr[1])+1, int(xr[2])):
        labels.add(text(str(value), 19).move_to([a.c2p(value, yr[0])[0], -2.5, 0]))
    for value in range(int(yr[0]), int(yr[1])+1, int(yr[2])):
        labels.add(text(str(value), 18).move_to([-5.55, a.c2p(xr[0], value)[1], 0]))
    return a, labels

def call_value(s, t, sigma=.3):
    if t <= 0:
        return max(s - 100, 0)
    d1 = (log(s / 100) + .5 * sigma * sigma * t) / (sigma * sqrt(t))
    d2 = d1 - sigma * sqrt(t)
    normal = lambda x: .5 * (1 + erf(x / sqrt(2)))
    return s * normal(d1) - 100 * normal(d2)

class FuturesMargin(Scene):
    def construct(self):
        beat(self, "Small deposit. How much exposure?", "One linear futures contract; $10 per point; costs excluded.")
        a, labels = axes([90,110,5],[-100,100,50],"Futures price","Profit ($)")
        long = a.plot(lambda x:10*(x-100),x_range=[90,110],color=TEAL)
        short = a.plot(lambda x:-10*(x-100),x_range=[90,110],color=CORAL)
        self.add(a,labels)
        self.play(Create(long),Create(short),run_time=4)
        self.add(text("Long",27,TEAL).move_to([4,1.65,0]),text("Short",27,CORAL).move_to([4,-1.7,0]))
        self.wait(5)
        self.play(FadeIn(Dot(a.c2p(106,60),color=GOLD)),
                  FadeIn(text("106: long +$60 / short −$60",30).move_to([0,2.3,0])),run_time=2)
        end(self)

        beat(self, "Settlement moves cash along the path", "Margin is collateral, not a purchase of the underlying.")
        balance = ValueTracker(200)
        counter = always_redraw(lambda: text(f"Margin balance: $ {balance.get_value():.0f}",49).move_to([0,.2,0]))
        price = text("Futures: 100",36).move_to([0,1.6,0])
        self.add(counter,price)
        self.wait(6)
        self.play(balance.animate.set_value(240),Transform(price,text("100 → 104: +$40",36,TEAL).move_to(price)),run_time=4)
        self.wait(4)
        self.play(balance.animate.set_value(210),Transform(price,text("104 → 101: −$30",36,CORAL).move_to(price)),run_time=4)
        self.add(text("Net: +$10",35,GOLD).move_to([0,-1.5,0]))
        end(self)

        beat(self, "The path can close the position", "$200 initial equity; $150 maintenance — teaching numbers only.")
        a,labels = axes([90,105,5],[100,250,50],"Futures price","Equity ($)")
        self.add(a,labels,a.plot(lambda x:200+10*(x-100),x_range=[90,105],color=TEAL))
        self.add(DashedLine(a.c2p(90,150),a.c2p(105,150),color=GOLD))
        price = ValueTracker(100)
        dot = always_redraw(lambda: Dot(a.c2p(price.get_value(),200+10*(price.get_value()-100)),color=CORAL))
        self.add(dot)
        self.wait(5)
        self.play(price.animate.set_value(94),run_time=7)
        self.play(FadeIn(text("94 → $140: below maintenance",30,GOLD).move_to([0,2.3,0])),run_time=2)
        end(self)

        beat(self, "A derivative can flatten exposure", "Ideal matched hedge at settlement; basis, costs and cash demands omitted.")
        a,labels = axes([60,140,20],[-40,140,40],"Settlement price","Value per unit ($)")
        spot = a.plot(lambda s:s,x_range=[60,140],color=BLUE)
        future = a.plot(lambda s:100-s,x_range=[60,140],color=CORAL)
        combined = a.plot(lambda s:100,x_range=[60,140],color=TEAL)
        self.add(a,labels,spot,future)
        self.add(text("Asset + short future",30).move_to([2,2.05,0]))
        self.wait(7)
        self.play(Transform(spot,combined),FadeOut(future),run_time=5)
        self.play(FadeIn(text("S + (100 − S) = 100",33,TEAL).move_to([0,2.65,0])),run_time=2)
        end(self)
