"""
Generic fitting procedure for all models except for the constrained dsl fitting procedure
"""
from lmfit import Model, Parameters
from pyIsoFit.core.model_fit_def import get_fit_tuples
from pyIsoFit.core.model_dicts import _MODEL_FUNCTIONS, _MODEL_PARAM_LISTS


def generic_fit(model,
                weights,
                y,
                guess,
                temps,
                cond=False,
                meth='leastsq',
                cust_bounds=None,
                fit_report=False,
                henry_constants=None,
                henry_off=False):
    """
    Fits any chosen isotherm model to experimental data and returns the results.

    :param weights:
        Used to perform a weighted fitting - by default this is set equal to self.x within the fitting.py module

    :return: tuple
        Returns a list of ModelResult objects corresponding to each dataframe [0] and a dictionary of parameters created
        by lmfit.
    """
    # Get function from model name string
    isotherm = _MODEL_FUNCTIONS[model]
    # Create instance of class Model with the chosen isotherm model function
    gmod = Model(isotherm)

    params = []
    values_dict = {}
    q_fix = None
    for i in range(len(weights)):
        # Create instance of class Parameters and create parameters using the get_fit_tuples function
        pars = Parameters()
        model_params = get_fit_tuples(model, guess, temps, i, cond, cust_bounds, henry_constants, henry_off, q_fix)
        pars.add_many(*model_params)
        results = gmod.fit(y[i], pars, x=weights[i], method=meth)

        params.append(results)
        values_dict[i] = results.values
        # Optional - call print fitting report generated by lmfit
        if fit_report:
            print("\n\n\n---- FIT REPORT FOR DATASET AT {temp} K -----".format(temp=temps[i]))
            print(results.fit_report())

        # If it is the first iteration and the model has a 'q' parameter, allocate q_fix a value.
        # This results in a float being passed into the q_fix argument of the get_fit_tuples function
        # resulting in a constrained fitting if the fitting condition is set to True
        if i == 0 and 'q' in _MODEL_PARAM_LISTS[model]:
            q_fix = results.values['q']
        elif i == 0 and 'n0' in _MODEL_PARAM_LISTS[model]:
            q_fix = results.values['n0']

        del results, pars

    return params, values_dict

