import pytest

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

#parameter - selector & descriptor
#selector - FilterSelector FieldSelector GenericSelector
#descriptor - RangeParameter CategoryParameter

#init, setup_checks, and setup_changes were moved directly from Will's code in parameters.py
def test_init():
    # inputs should be initialisable
    Parameter(FieldSelector(object_name='NonRes Fixed Assembly Window', field_name='UFactor'),
              value_descriptor=RangeParameter(min_val=0.1, max_val=5))
    wwr()
    wwr(name='other')
    print('Parameters initialised')

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


#TODO: look into fixing this
def test_setup_checks():
    #try excepts were updated to asserts and now the test fails, no exceptions are being raised and it seems to be in 3rd party code

    idf = ef.get_idf()
    assert len(idf.idfobjects['FENESTRATIONSURFACE:DETAILED']) == 21, 'bad idf'

    # eppy key-inputs should reject bad key values at setup
    r: Parameter = Parameter(FieldSelector(class_name='invalid', field_name='any'))

    #when exception raising is implemented properly uncomment this test, for now it does nothing

    #with pytest.raises(Exception):
    #    r.setup(idf)
    #print('Invalid object key detected successfully.')
    #r = Parameter(FieldSelector(object_name='NonRes Fixed Assembly Window', field_name='invalid'))
    #with pytest.raises(Exception):
    #    r.setup(idf)
    #print('Invalid property detected successfully.')

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


def test_setup_changes():
    idf = ef.get_idf()

    r1 = Parameter(FieldSelector(object_name='NonRes Fixed Assembly Window', field_name='UFactor'),
                   value_descriptor=RangeParameter(min_val=0.1, max_val=5))
    r2 = wwr()
    r3 = wwr(name='other')

    r1.setup(idf)
    r2.setup(idf)
    assert len(idf.idfobjects['FENESTRATIONSURFACE:DETAILED']) == 4, 'bug in r2.setup'

    idf = ef.get_idf()
    assert len(idf.idfobjects['FENESTRATIONSURFACE:DETAILED']) == 21, 'bad idf'
    r3.setup(idf)
    assert len(idf.idfobjects['FENESTRATIONSURFACE:DETAILED']) == 4, 'bug in r3.setup'

    print('setup tests done')

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


def test_custom_evaluation():
    """check to see if descriptors display as intended, and check to make sure custom evaluations work with EvaluatorSR"""

    #create the descriptors
    zero_to_nine = RangeParameter(min_val = 0, max_val=9)
    single_digit_integers = CategoryParameter(options=[0,1,2,3,4,5,6,7,8,9])
    text_example = CategoryParameter(options=['a', 'b', 'c', 'other'])

    #create the parameters and the problem
    parameters = [
        Parameter(value_descriptor=zero_to_nine, name='0-9'),
        Parameter(value_descriptor=single_digit_integers, name='single digit'),
        Parameter(value_descriptor=text_example, name='text')
    ]
    problem = Problem(parameters, outputs=['output'])

    #create the sampling distribution (seeded with only one output that should give     4.939321535345923	7	c	34.575251 after evaluating)
    samples = sampling.dist_sampler(sampling.seeded_sampler, problem, num_samples=1)
    values = [samples.iloc[0]['0-9'], samples.iloc[0]['single digit'], samples.iloc[0]['text']]
    assert np.isclose(values[0], 4.939321535345923) and values[1:] == [7, 'c'], f'Unexpected sample values: {values}'

    #custom evaluation function from the jupyter notebook
    def evaluation_function(values):
        x,y,z = values
        if z == 'other':
            return (0,), ()
        else:
            return (x * y,), ()

    evaluator = EvaluatorSR(evaluation_function, problem)
    # The evaluator will use this objective by default
    outputs = evaluator.df_apply(samples ,keep_input=True)
    result = outputs.iloc[0]['output']
    print(result)
    assert np.isclose(result, 34.57525074742146), f'Unexpected evaluation result: {result}'

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