import pytest
import pandas as pd
from pandas import DataFrame as DF
import numpy as np

import eppy_funcs as ef
from evaluator import EvaluatorEP, EvaluatorSR
from parameters import RangeParameter, CategoryParameter, Parameter, FieldSelector
from problem import EPProblem
import sampling

#Some code taken and adapted from example notebooks, made to work through pytest

@pytest.fixture
def building():
    return ef.get_building()


@pytest.fixture
def problem():
    problem = EPProblem([
        Parameter(
            FieldSelector(object_name='Mass NonRes Wall Insulation', field_name='Thickness'),
            RangeParameter(min_val = 0.01, max_val=0.99)),
        Parameter(
            FieldSelector(class_name='Construction', object_name='ext-slab', field_name='Outside Layer'),
            CategoryParameter(options=('HW CONCRETE', 'Invalid Material')))])
    return problem


@pytest.fixture
def samples(problem):
    #seeded_sampler results in indexes 0-3 being Invalid Material and 4 being HW CONCRETE
    samples = sampling.dist_sampler(sampling.seeded_sampler, problem, 5)
    return samples


def test_exception_throwing(building, problem, samples):
    """test to make sure exceptions are thrown or ignored depending on the error_mode"""

    #check that an exception is raised with FailFast mode
    with pytest.raises(Exception):
        evaluator = EvaluatorEP(problem, building, error_mode='FailFast').df_apply(samples)

    #check that no exceptions are raised in the other mode
    try:
        evaluator = EvaluatorEP(problem, building, error_mode='Silent').df_apply(samples)
    except Exception as e:
        assert 0

    #change this to 0 to see stdout and stderr
    assert 1


def test_error_values(building, problem, samples):
    """check that automatic error handling will assign the desired error values"""

    #check that the default error value is assigned to invalid materials
    evaluator = EvaluatorEP(problem, building, error_mode='Silent')
    results = evaluator.df_apply(samples)
    value = results.iloc[0]['Electricity:Facility']
    assert value == np.inf, f'Invalid material not assigned the default error value, value assigned was: {value}'

    #check that a custom error value is assigned to invalid materials
    error_value=((-1,), ())
    evaluator = EvaluatorEP(problem, building, error_mode='Silent', error_value=error_value)
    results = evaluator.df_apply(samples)
    value = results.iloc[0]['Electricity:Facility']
    assert value == -1, f'Invalid material not assigned the correct error value, value assigned was: {value}'

    #check that valid inputs aren't assigned error values
    value = results.iloc[4]['Electricity:Facility']
    assert value != -1, f'Valid material was assigned the error value: {error_value}'

    #change this to 0 to see stdout and stderr
    assert 1
