import numpy as np

from nmreval.utils.constants import R_joule as R


class TNMH:
    type = 'DSC'
    name = 'TNMH model'
    equation = r''
    params = [r'\tau_{g}', 'x', r'\beta', r'\Delta H', 'T_{g}', 'rate']
    bounds = [(0, None), (0, 1), (0, 1), (0, None), (0, None), (0, None)]

    @staticmethod
    def func(x: np.ndarray, tau_g: float, xx: float, beta: float, energy: float, tg: float, rate: float) -> np.ndarray:
        model_temp = np.r_[x[::-1], x[1:]]

        curve = TNMH.tnm_function(model_temp, tau_g, xx, beta, energy, tg, rate)[x.size - 1:]
        res = np.gradient(curve, x)

        return res

    @staticmethod
    def tnm_function(x: np.ndarray, tau_g: float, xx: float, beta: float, energy: float, tg: float, rate: float) -> np.ndarray:
        step = x.size

        Tf = np.empty(step)
        Tf[0] = x[0]

        delta_temp = np.diff(x)
        delta_time = np.abs(delta_temp) * 60 / rate

        tau = np.empty(step)
        dt_by_tau = np.zeros(step)
        temp_0 = x[0]

        for i in range(0, step - 1):
            tau[i] = TNMH.relax(x[i+1], Tf[i], tau_g, tg, energy, xx)
            dt_by_tau[:i] += delta_time[i] / tau[i]
            Tf[i + 1] = np.sum(delta_temp[:i] * (1 - np.exp(-dt_by_tau[:i] ** beta))) + temp_0

        return Tf

    @staticmethod
    def relax(t, tf, tau_g, t_glass, ea, x):
        h = ea/R
        return tau_g * np.exp((x*h / t) + ((1 - x) * h / tf) - h / t_glass)
