import torch
from torch import nn
import torch.optim as optim
from pathlib import Path
import importlib
import sys

root = Path(__file__).parent.parent.parent
sys.path.append(str(root)+"/src/")
from setting import Setting
import utilities as util

############################################################################################################################

# COMPILE HERE 
#simul_type = "Single"
#simul_type = "NeuronSweep"
simul_type = "FeaturesUsed"

if simul_type == 'Single':
    batch_size          = 16 
    learning_rate       = 0.01 
    epochs              = 200 
    overlap_of_samples  = 0 
    samples_per_param   = 1 
    start_date          = "2021-04-03 09:30:00"
    end_date            = "2021-05-30 09:30:00"
    parameters_to_use   = ['impedance_phase','impedance_modulus','hour']
    outputs             = ['Status']
    plants_to_use       = ["pianta1","pianta2","pianta3","pianta4"]
    loss_fn             = nn.BCEWithLogitsLoss()
    
    model               = nn.Sequential()
    model.add_module('InputLayer'   , nn.Linear(3,10))
    model.add_module('Activation0'  , nn.ReLU())
    model.add_module('Output'       , nn.Linear(10,1))
   
    optimizer = optim.SGD(params=model.parameters(), lr=learning_rate )
    
    dataset_settings = [
         {
            "param_name"                : "impedance_modulus",
            "input_name"                : "impedance_modlus",
            "norm_data_range"           : None, 
            "norm_data_median"          : None,
            "transform_function"        : None,
            "transform_function_kwargs" : {},
            "filter"                    : None,  # util.simpleMovingAverage,  # None,
            "filter_kwargs"             : {"N": 12},  # {"N": 24},
            "constrain_min"             : None,
            "constrain_max"             : None 
        },
        {
            "param_name"                : "impedance_phase",
            "input_name"                : "impedance_phase",
            "norm_data_range"           : None,
            "norm_data_median"          : None,
            "transform_function"        : None,
            "transform_function_kwargs" : {},
            "filter"                    : None,  # util.simpleMovingAverage,  # None,
            "filter_kwargs"             : {"N": 12},  # {"N": 24},
            "constrain_min"             : None,
            "constrain_max"             : None 
        },
        {
            "param_name"                : "moisture",
            "input_name"                : "Moisture [KPa]",
            "norm_data_range"           : 200,
            "norm_data_median"          : -100,
            "transform_function"        : None,
            "transform_function_kwargs" : {},
            "filter"                    : None,  # util.simpleMovingAverage,  # None,
            "filter_kwargs"             : {"N": 12},  # {"N": 24},
            "constrain_min"             : -200,
            "constrain_max"             : -1
        },
        {
            "param_name"                : "temperature",
            "input_name"                : "Temperature [C]",
            "norm_data_range"           : 50,
            "norm_data_median"          : 25,
            "transform_function"        : None,
            "transform_function_kwargs" : {},
            "filter"                    : None,  # None,
            "filter_kwargs"             : {"N": 12},
            "constrain_min"             : 0,
            "constrain_max"             : 50
        },
        {
            "param_name"                : "Status",
            "input_name"                : "Status",
            "norm_data_range"           : 1,
            "norm_data_median"          : 0.5,
            "transform_function"        : None,
            "transform_function_kwargs" : {},
            "filter"                    : None,
            "filter_kwargs"             : {"N": 24},
            "constrain_min"             : 0,
            "constrain_max"             : 1 
        },
        {
            "param_name"                : "hour",
            "input_name"                : "Date",
            "norm_data_range"           : None,
            "norm_data_median"          : None,
            "transform_function"        : util.getHour,
            "transform_function_kwargs" : {},
            "filter"                    : None,
            "filter_kwargs"             : {"N": 24},
            "constrain_min"             : None,
            "constrain_max"             : None
        },
        {
            "param_name"                : "AirHumidity",
            "input_name"                : "Air Humidity [RH]",
            "norm_data_range"           : 100,
            "norm_data_median"          : 50,
            "transform_function"        : None,
            "transform_function_kwargs" : {},
            "filter"                    : None,  # None,
            "filter_kwargs"             : {"N": 12},
            "constrain_min"             : 100,
            "constrain_max"             : 0 
        },
        {
            "param_name"                : "Ambient Light",
            "input_name"                : "Ambient Light [lux]",
            "norm_data_range"           : 50000,
            "norm_data_median"          : 25000,
            "transform_function"        : None,
            "transform_function_kwargs" : {},
            "filter"                    : None,  # None,
            "filter_kwargs"             : {"N":12},
            "constrain_min"             : 0,
            "constrain_max"             : 50000 
        },
        {
            "param_name"                : "day_of_year",
            "input_name"                : "Date",
            "norm_data_range"           : 364,
            "norm_data_median"          : 183,
            "transform_function"        : util.getDayOfYear,
            "transform_function_kwargs" : {},
            "filter"                    : None,
            "filter_kwargs"             : {},
            "constrain_min"             : None,
            "constrain_max"             : None
        }
    
    ]
    ############################## END OF COMPILE SECTION ##########################
    
    user_setting = Setting(simul_type)
    user_setting.set_batch_size(batch_size)
    user_setting.set_learning_rate(learning_rate)
    user_setting.set_epochs(epochs)
    user_setting.set_overlap_of_samples(overlap_of_samples)
    user_setting.set_samples_per_param(samples_per_param)
    user_setting.set_start_date(start_date)
    user_setting.set_end_date(end_date)
    user_setting.set_parameters_to_use(parameters_to_use)
    user_setting.set_outputs(outputs)
    user_setting.set_plants_to_use(plants_to_use)
    user_setting.set_dataset_settings(dataset_settings) 
    user_setting.set_simul_type(simul_type)
    user_setting.set_loss_fn(loss_fn)
    user_setting.set_optimizer(optimizer)
    user_setting.set_model(model)



elif simul_type == 'FeaturesUsed':

    batch_size          = 16 
    learning_rate       = 0.01 
    epochs              = 200 
    overlap_of_samples  = 0 
    samples_per_param   = 1 
    start_date          = "2021-04-03 09:30:00"
    end_date            = "2021-05-30 09:30:00"
    parameters_to_use   = ['impedance_phase','impedance_modulus','hour'],['impedance_modulus','hour']
    layers              = [10,20]
    activations         = (nn.ReLU(),nn.ReLU())
    outputs             = ['Status']
    plants_to_use       = ["pianta1","pianta2","pianta3","pianta4"]
    loss_fn             = nn.BCEWithLogitsLoss()
    output_neurons      = 2
    dataset_settings    = [
             {
                "param_name"                : "impedance_modulus",
                "input_name"                : "impedance_modlus",
                "norm_data_range"           : None, 
                "norm_data_median"          : None,
                "transform_function"        : None,
                "transform_function_kwargs" : {},
                "filter"                    : None,  # util.simpleMovingAverage,  # None,
                "filter_kwargs"             : {"N": 12},  # {"N": 24},
                "constrain_min"             : None,
                "constrain_max"             : None 
            },
            {
                "param_name"                : "impedance_phase",
                "input_name"                : "impedance_phase",
                "norm_data_range"           : None,
                "norm_data_median"          : None,
                "transform_function"        : None,
                "transform_function_kwargs" : {},
                "filter"                    : None,  # util.simpleMovingAverage,  # None,
                "filter_kwargs"             : {"N": 12},  # {"N": 24},
                "constrain_min"             : None,
                "constrain_max"             : None 
            },
            {
                "param_name"                : "moisture",
                "input_name"                : "Moisture [KPa]",
                "norm_data_range"           : 200,
                "norm_data_median"          : -100,
                "transform_function"        : None,
                "transform_function_kwargs" : {},
                "filter"                    : None,  # util.simpleMovingAverage,  # None,
                "filter_kwargs"             : {"N": 12},  # {"N": 24},
                "constrain_min"             : -200,
                "constrain_max"             : -1
            },
            {
                "param_name"                : "temperature",
                "input_name"                : "Temperature [C]",
                "norm_data_range"           : 50,
                "norm_data_median"          : 25,
                "transform_function"        : None,
                "transform_function_kwargs" : {},
                "filter"                    : None,  # None,
                "filter_kwargs"             : {"N": 12},
                "constrain_min"             : 0,
                "constrain_max"             : 50
            },
            {
                "param_name"                : "Status",
                "input_name"                : "Status",
                "norm_data_range"           : 1,
                "norm_data_median"          : 0.5,
                "transform_function"        : None,
                "transform_function_kwargs" : {},
                "filter"                    : None,
                "filter_kwargs"             : {"N": 24},
                "constrain_min"             : 0,
                "constrain_max"             : 1 
            },
            {
                "param_name"                : "hour",
                "input_name"                : "Date",
                "norm_data_range"           : None,
                "norm_data_median"          : None,
                "transform_function"        : util.getHour,
                "transform_function_kwargs" : {},
                "filter"                    : None,
                "filter_kwargs"             : {"N": 24},
                "constrain_min"             : None,
                "constrain_max"             : None
            },
            {
                "param_name"                : "AirHumidity",
                "input_name"                : "Air Humidity [RH]",
                "norm_data_range"           : 100,
                "norm_data_median"          : 50,
                "transform_function"        : None,
                "transform_function_kwargs" : {},
                "filter"                    : None,  # None,
                "filter_kwargs"             : {"N": 12},
                "constrain_min"             : 100,
                "constrain_max"             : 0 
            },
            {
                "param_name"                : "Ambient Light",
                "input_name"                : "Ambient Light [lux]",
                "norm_data_range"           : 50000,
                "norm_data_median"          : 25000,
                "transform_function"        : None,
                "transform_function_kwargs" : {},
                "filter"                    : None,  # None,
                "filter_kwargs"             : {"N":12},
                "constrain_min"             : 0,
                "constrain_max"             : 50000 
            },
            {
                "param_name"                : "day_of_year",
                "input_name"                : "Date",
                "norm_data_range"           : 364,
                "norm_data_median"          : 183,
                "transform_function"        : util.getDayOfYear,
                "transform_function_kwargs" : {},
                "filter"                    : None,
                "filter_kwargs"             : {},
                "constrain_min"             : None,
                "constrain_max"             : None
            }
        ]
        
    user_setting = Setting(simul_type)
    user_setting.set_batch_size(batch_size)
    user_setting.set_learning_rate(learning_rate)
    user_setting.set_epochs(epochs)
    user_setting.set_overlap_of_samples(overlap_of_samples)
    user_setting.set_samples_per_param(samples_per_param)
    user_setting.set_start_date(start_date)
    user_setting.set_end_date(end_date)
    user_setting.set_parameters_to_use(parameters_to_use)
    user_setting.set_outputs(outputs)
    user_setting.set_output_neurons(output_neurons)
    user_setting.set_plants_to_use(plants_to_use)
    user_setting.set_dataset_settings(dataset_settings) 
    user_setting.set_simul_type(simul_type)
    user_setting.set_loss_fn(loss_fn)
    user_setting.set_layers(layers)
    user_setting.set_activations(activations)
else: 
    raise Exception("Invalid simulation type selected")