# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_core.ipynb.

# %% auto 0
__all__ = ['CalibrationModel']

# %% ../nbs/00_core.ipynb 3
import pandas as pd
import scipy as sp
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from dataclasses import dataclass
# from scipy.stats import t
import typing


# %% ../nbs/00_core.ipynb 6
class CalibrationModel:

    def __init__(self, x, y, test_replicates):
      
        self.x = x
        self.y = y
        self.slope = None
        self.intercept = None
        self.r_squared = None
        self.std_err = None
        self.test_replicates = test_replicates
        self.cal_line_points = self.x.shape[0]
        self.df_resid = self.cal_line_points - 2

    def fit_ols(self):

        self.slope, self.intercept, self.r_squared, self.std_err, _ = sp.stats.linregress(self.x, self.y)
    
    def calculate_fitted_values(self):
        
        self.fitted_values = self.slope * self.x + self.intercept

   
    def inverse_prediction(self, unknown):

        if len(unknown) > 1:
            y = np.mean(unknown)
        else:
            y = unknown[0]
       
        return (y - self.intercept)/self.slope
    
    def calculate_sse(self):
        self.calculate_fitted_values()
        return np.sum((self.fitted_values - self.y) **2)
    
    def calculate_syx(self):
        return np.sqrt((self.calculate_sse())/(len(self.x)-2))

    def get_t_value(self,alpha):
        return sp.stats.t.ppf(1 - alpha/2, self.df_resid)

    def calculate_uncertainty(self):
        return self.calculate_sxhat() * self.get_t_value(0.05)
    
    def calculate_sxhat(self):
        return (self.calculate_syx() / self.slope) * np.sqrt( 1/ self.test_replicates + 1 / self.cal_line_points) 
    
    def fit_model(self):
        self.fit_ols()
        self.calculate_uncertainty()
        self.tabulate_results()

    def tabulate_results(self):
        print(f"Calibration curve")
        print(f"R2 = {self.r_squared}")
        print(f"Slope = {self.slope}")
        print(f"Intercept = {self.intercept}")
        print(f"Uncertainity = {self.calculate_uncertainty()}")
        # print(f"Prediction = {self.inverse_prediction()}")
    


# %% ../nbs/00_core.ipynb 7
# def plot_calibration_curve(model, df, response_variable):

#         fig, ax = plt.subplots(1, 1, figsize=(5, 5))
#         sns.regplot(x="concentration", y=response_variable, data=df)
#         # ax.annotate(f"Predicted value = {model.inverse_prediction():.2f}", xy=(0.5, 0.9), xycoords='axes fraction', fontsize=9, ha='center', va='center')
#         # ax.axvline(x=model.inverse_prediction(), color='red', linestyle='--')
#         # ax.axvline(x=model.inverse_prediction() + model.calculate_uncertainty(), color='blue', linestyle='--')
#         # ax.axvline(x=model.inverse_prediction() - model.calculate_uncertainty(), color='blue', linestyle='--')
#         # ax.set_title('Calibration Curve')
#         # ax.set_xlabel('Concentration (v/v%)')
#         # ax.set_ylabel('Peak Value')
#         # ax.annotate(f"R-squared = {model.rsquared:.3f}", xy=(0.5, 0.8), xycoords='axes fraction', fontsize=9, ha='center', va='center')
#         # ax.annotate(f"Regression formula: y = {model.get_params()[0]:.3f} * x + {model.get_params()[1]:.3f}", xy=(0.5, 0.7), xycoords='axes fraction', fontsize=9, ha='center', va='center')

#         plt.tight_layout()
#         plt.show()
