import numpy as np
from finRav.price_models._price_model_base import PriceModel
from finRav.stoch.fractional_brownian_motion import fBM

class LogNormalPriceModel(PriceModel):
    r"""
    Lognormal Price Model (GBM / fGBM)
    ==================================

    Unified formulation for both standard and fractional Geometric Brownian Motion:

    .. math::

        S_t = S_0 \exp\!\Big( \mu t - \tfrac{1}{2}\sigma^2 t^{2H} + \sigma B_t^H \Big)

    where:
      - \( B_t^H \) is the fractional Brownian motion with Hurst exponent \(H\),
      - \(H=0.5\) recovers the standard Brownian motion case (GBM).

    Notes
    -----
    - For H = 0.5 → standard GBM:
      \[
      S_t = S_0 e^{(\mu - \tfrac{1}{2}\sigma^2)t + \sigma W_t}
      \]
    - For H ≠ 0.5 → fractional GBM with long-memory dynamics.
    - The variance of increments scales as \( t^{2H} \), introducing persistence or anti-persistence.

    Parameters
    ----------
    S0 : float
        Initial price of the asset.
    mu : float
        Drift parameter (per time unit).
    sigma : float
        Volatility parameter (per time unit).
    H : float, default=0.5
        Hurst exponent (0 < H < 1). H=0.5 → GBM, otherwise fGBM.

    Methods
    -------
    generate(B, t)
        Generate the price path from a Brownian/fractional Brownian driver.

    Examples
    --------
    >>> import numpy as np
    >>> from finRav.price_models._lognormal_model import LogNormalPriceModel
    >>> from finRav.stoch.fractional_brownian_motion import fBM

    >>> fbm = fBM(N=100, H=0.7, dt=1/252)
    >>> t, B = fbm.simulate()
    >>> model = LogNormalPriceModel(S0=100, mu=0.05, sigma=0.2, H=0.7)
    >>> S = model.generate(B, t)
    >>> S.shape
    (100,)
    """
    def __init__(self, S0: float, mu: float, sigma: float, H: float = 0.5):
        super().__init__(S0=S0, mu=mu, sigma=sigma, H=H)

    def generate(self, B: np.ndarray, t: np.ndarray) -> np.ndarray:
        """
        Generate a single simulated lognormal path.

        Parameters
        ----------
        B : np.ndarray
            The Brownian or fractional Brownian motion driver path.
        t : np.ndarray
            Time grid corresponding to `B`.

        Returns
        -------
        np.ndarray
            Simulated lognormal price path S_t.
        """
        logS = np.log(self.S0) + self.mu * t - 0.5 * (self.sigma ** 2) * (t ** (2 * self.H)) + self.sigma * B
        return np.exp(logS)
