from __future__ import annotations

import math
from dataclasses import dataclass

# Helpers
def _norm_pdf(x: float) -> float:
    return math.exp(-0.5 * x * x) / math.sqrt(2 * math.pi)


def _norm_cdf(x: float) -> float:
    return 0.5 * (1 + math.erf(x / math.sqrt(2)))


# Greeks container
@dataclass
class Greeks:
    price: float
    delta: float
    gamma: float
    vega: float
    theta: float
    rho: float
    charm: float
    vanna: float
    vomma: float


# Black–Scholes + Greeks
def bs_greeks(
    *,
    S: float,
    K: float,
    T: float,
    r: float,
    sigma: float,
    is_call: bool,
) -> Greeks:
    """
    Black–Scholes price and Greeks.
    """

    if S <= 0 or K <= 0 or T <= 0 or sigma <= 0:
        return Greeks(*(math.nan,) * 9)

    sqrtT = math.sqrt(T)

    d1 = (math.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * sqrtT)
    d2 = d1 - sigma * sqrtT

    pdf = _norm_pdf(d1)
    cdf1 = _norm_cdf(d1)
    cdf2 = _norm_cdf(d2)

    # price, delta, rho
    if is_call:
        price = S * cdf1 - K * math.exp(-r * T) * cdf2
        delta = cdf1
        rho = K * T * math.exp(-r * T) * cdf2 / 100
    else:
        price = K * math.exp(-r * T) * _norm_cdf(-d2) - S * _norm_cdf(-d1)
        delta = cdf1 - 1
        rho = -K * T * math.exp(-r * T) * _norm_cdf(-d2) / 100

    # first-order
    gamma = pdf / (S * sigma * sqrtT)
    vega = S * pdf * sqrtT / 100

    theta = (
        -S * pdf * sigma / (2 * sqrtT)
        - (r * K * math.exp(-r * T) * cdf2 if is_call else
           -r * K * math.exp(-r * T) * _norm_cdf(-d2))
    ) / 365

    # second-order
    vanna = -pdf * d2 / sigma / 100
    vomma = vega * d1 * d2 / sigma / 100

    charm = (
        -pdf * (2 * r * T - d2 * sigma * sqrtT)
        / (2 * T * sigma * sqrtT)
    )
    if not is_call:
        charm += r * math.exp(-r * T)
    charm /= 365

    return Greeks(
        price=price,
        delta=delta,
        gamma=gamma,
        vega=vega,
        theta=theta,
        rho=rho,
        charm=charm,
        vanna=vanna,
        vomma=vomma,
    )