from __future__ import unicode_literals
from datetime import date

import unittest

import nose

from ldclient.enums import QueryConditionValueType
from ldclient.__experimental.experimental_models import (
    Query,
    QueryDateRangeObservationCondition,
    QueryLiveReportCondition,
    QueryObservationCondition,
    QueryProjectCondition,
    QueryRangedObservationCondition,
    QueryRelativeDateObservationCondition,
    QueryStructureCondition,
)
from ldclient.__experimental.experimental_enums import QueryObservationConditionOperator, QueryConditionType


class ExperimentalLDModelsUnitTests(unittest.TestCase):

    maxDiff = None

    def testQueryObservationCondition(self):
        query_condition_def = {
            'addable_column_id': '113',
            'concentrations': None,
            'concentration_units': None,
            'create_assay_limited_addable_column': False,
            'delimiter': '__DEBUG__',
            'id': '1',
            'inverted': False,
            'observation_date_inverted': False,
            'observation_date_value': None,
            'observation_date_value_type': None,
            'operator': QueryObservationConditionOperator.EQUALS,
            'protocols': None,
            'related_column_conditions': [],
            'type': QueryConditionType.OBSERVATION,
            'units': None,
            'value': 'abc',
            'value_type': QueryConditionValueType.VALUE
        }
        query_condition_obj = QueryObservationCondition.from_dict(query_condition_def)
        self.assertDictEqual(query_condition_def, query_condition_obj.as_dict())
        defined = QueryObservationCondition('113', value=['(defined)'])
        categorical = QueryObservationCondition('113', value=['1', '2'])
        self.assertEqual(defined.as_dict()['value'], '(defined)')
        self.assertEqual(categorical.as_dict()['value'], '1__DEBUG__2')

    def testQueryRangedObservationCondition(self):
        defined_obj = QueryRangedObservationCondition('113', value=(None, None))
        lower_bound_obj = QueryRangedObservationCondition('113', value=(0, None))
        upper_bound_obj = QueryRangedObservationCondition('113', value=(None, 0))
        self.assertEqual(defined_obj.as_dict()['value'], '(defined)')
        self.assertEqual(lower_bound_obj.as_dict()['value'], '[0,]')
        self.assertEqual(upper_bound_obj.as_dict()['value'], '[,0]')
        defined_from_dict = QueryRangedObservationCondition.from_dict({
            'addable_column_id': '113',
            'value': '(defined)'
        })
        lower_bound_from_dict = QueryRangedObservationCondition.from_dict({
            'addable_column_id': '113',
            'value': '[0,]'
        })
        upper_bound_from_dict = QueryRangedObservationCondition.from_dict({
            'addable_column_id': '113',
            'value': '[,0]'
        })
        self.assertAlmostEqual(defined_from_dict.value[0], None)
        self.assertAlmostEqual(defined_from_dict.value[1], None)
        self.assertEqual(lower_bound_from_dict.value, (0, None))
        self.assertEqual(upper_bound_from_dict.value, (None, 0))

    def testDateRangeQueryConditions(self):
        defined_obj = QueryDateRangeObservationCondition('2', value=(None, None))
        lower_bound_obj = QueryDateRangeObservationCondition('2', value=(date(2021, 5, 26), None))
        upper_bound_obj = QueryDateRangeObservationCondition('2', value=(None, date(2021, 5, 26)))
        self.assertEqual(defined_obj.as_dict()['value'], '(defined)')
        self.assertEqual(lower_bound_obj.as_dict()['value'], '[2021-05-26,]')
        self.assertEqual(upper_bound_obj.as_dict()['value'], '[,2021-05-26]')
        defined_from_dict = QueryDateRangeObservationCondition.from_dict({
            'addable_column_id': '2',
            'value': '(defined)'
        })
        lower_bound_from_dict = QueryDateRangeObservationCondition.from_dict({
            'addable_column_id': '2',
            'value': '[2021-05-26,]'
        })
        upper_bound_from_dict = QueryDateRangeObservationCondition.from_dict({
            'addable_column_id': '2',
            'value': '[,2021-05-26]'
        })
        self.assertAlmostEqual(defined_from_dict.value[0], None)
        self.assertAlmostEqual(defined_from_dict.value[1], None)
        self.assertEqual(lower_bound_from_dict.value, (date(2021, 5, 26), None))
        self.assertEqual(upper_bound_from_dict.value, (None, date(2021, 5, 26)))

    def testRelativeDateQueryConditions(self):
        relative = QueryRelativeDateObservationCondition('2')
        self.assertEqual(relative.as_dict()['value'], "7")

    def testQuery(self):
        query_def = {
            'id': '11226',
            'frequency': 'periodic',
            'active': False,
            'auto_update_results': False,
            'clear_report_on_search': False,
            'live_report_id': '53027',
            'view_type': 'complex',
            'expression': ' 1 & 2 & 3 | 4 & 5 & 6 & 7 8 | 9 ',
            'compound_return_type': 'both',
            'data_source': {
                'inverted': False,
                'value': '203,1,153,2,3,103,253'
            },
            'entity_return_type': ['compound', 'formulation', 'fragment'],
            'conditions': [
                {
                    'delimiter': '',
                    'type': QueryConditionType.STRUCTURE,
                    'id': '1',
                    'inverted': False,
                    'value_type': QueryConditionValueType.SIMILARITY,
                    'value': '<cml xmlns=\'http://www.chemaxon.com\' version=\'ChemAxon file format v20.9.0, generated by vunknown\' xmlns:xsi=\'http://www.w3.org/2001/XMLSchema-instance\' xsi:schemaLocation=\'http://www.chemaxon.com http://www.chemaxon.com/marvin/schema/mrvSchema_20_9_0.xsd\'><MDocument><MChemicalStruct><molecule molID=\'m1\'><atomArray><atom id=\'a1\' elementType=\'C\' x2=\'-1.895926666665918\' y2=\'1.873426654345919\'/><atom id=\'a2\' elementType=\'C\' x2=\'-3.2294733226642123\' y2=\'1.10342666050592\'/><atom id=\'a3\' elementType=\'C\' x2=\'-3.2294733226642123\' y2=\'-0.4367599938392539\'/><atom id=\'a4\' elementType=\'C\' x2=\'-1.895926666665918\' y2=\'-1.2067599876792539\'/><atom id=\'a5\' elementType=\'C\' x2=\'-0.5621933440024536\' y2=\'-0.4367599938392539\'/><atom id=\'a6\' elementType=\'C\' x2=\'-0.5621933440024536\' y2=\'1.10342666050592\'/></atomArray><bondArray><bond id=\'b1\' atomRefs2=\'a1 a2\' order=\'2\'/><bond id=\'b2\' atomRefs2=\'a2 a3\' order=\'1\'/><bond id=\'b3\' atomRefs2=\'a3 a4\' order=\'2\'/><bond id=\'b4\' atomRefs2=\'a4 a5\' order=\'1\'/><bond id=\'b5\' atomRefs2=\'a5 a6\' order=\'2\'/><bond id=\'b6\' atomRefs2=\'a6 a1\' order=\'1\'/></bondArray></molecule></MChemicalStruct></MDocument></cml>',
                    'scaffold_id': '16369',
                    'threshold': 0.01
                },
                {
                    'type': QueryConditionType.OBSERVATION,
                    'id': '2',
                    'inverted': False,
                    'value_type': QueryConditionValueType.NUMERIC_RANGE,
                    'value': '(defined)',
                    'addable_column_id': '1402',
                    'delimiter': '',
                    'operator': QueryObservationConditionOperator.EQUALS,
                    'observation_date_inverted': False,
                    'observation_date_value_type': None,
                    'observation_date_value': None,
                    'create_assay_limited_addable_column': False,
                    'protocols': None,
                    'units': None,
                    'concentrations': None,
                    'concentration_units': None,
                    'related_column_conditions': []
                },
                {
                    'addable_column_id': '29055',
                    'type': QueryConditionType.OBSERVATION,
                    'id': '3',
                    'inverted': False,
                    'value_type': QueryConditionValueType.VALUE,
                    'value': '(defined)',
                    'delimiter': '__DEBUG__',
                    'operator': QueryObservationConditionOperator.EQUALS,
                    'observation_date_inverted': False,
                    'observation_date_value_type': None,
                    'observation_date_value': None,
                    'create_assay_limited_addable_column': False,
                    'protocols': None,
                    'units': None,
                    'concentrations': None,
                    'concentration_units': None,
                    'related_column_conditions': []
                },
                {
                    'type': QueryConditionType.OBSERVATION,
                    'id': '4',
                    'inverted': False,
                    'value_type': QueryConditionValueType.VALUE,
                    'value': '1',
                    'addable_column_id': '20788',
                    'delimiter': '__DEBUG__',
                    'operator': QueryObservationConditionOperator.EQUALS,
                    'observation_date_inverted': False,
                    'observation_date_value_type': None,
                    'observation_date_value': None,
                    'create_assay_limited_addable_column': False,
                    'protocols': None,
                    'units': None,
                    'concentrations': None,
                    'concentration_units': None,
                    'related_column_conditions': []
                },
                {
                    'type': QueryConditionType.LIVE_REPORT,
                    'id': '5',
                    'inverted': False,
                    'value_type': QueryConditionValueType.VALUE,
                    'value': '35692',
                    'delimiter': ','
                },
                {
                    'type': QueryConditionType.PROJECT,
                    'id': '6',
                    'inverted': False,
                    'value_type': QueryConditionValueType.VALUE,
                    'value': '0',
                    'delimiter': ','
                },
                {
                    'type': QueryConditionType.OBSERVATION,
                    'id': '7',
                    'inverted': False,
                    'value_type': QueryConditionValueType.NUMERIC_RANGE,
                    'value': '[0.0,2.0]',
                    'addable_column_id': '20787',
                    'delimiter': '',
                    'operator': QueryObservationConditionOperator.EQUALS,
                    'observation_date_inverted': False,
                    'observation_date_value_type': None,
                    'observation_date_value': None,
                    'create_assay_limited_addable_column': False,
                    'protocols': None,
                    'units': None,
                    'concentrations': None,
                    'concentration_units': None,
                    'related_column_conditions': []
                },
                {
                    'type': QueryConditionType.OBSERVATION,
                    'id': '8',
                    'inverted': False,
                    'value_type': QueryConditionValueType.DATE_RANGE,
                    'value': '[2021-05-26,]',
                    'addable_column_id': '2',
                    'delimiter': '',
                    'operator': QueryObservationConditionOperator.EQUALS,
                    'observation_date_inverted': False,
                    'observation_date_value_type': None,
                    'observation_date_value': None,
                    'create_assay_limited_addable_column': False,
                    'protocols': None,
                    'units': None,
                    'concentrations': None,
                    'concentration_units': None,
                    'related_column_conditions': []
                },
                {
                    'type': QueryConditionType.OBSERVATION,
                    'id': '9',
                    'inverted': False,
                    'value_type': QueryConditionValueType.RELATIVE_DATE,
                    'value': '7',
                    'addable_column_id': '2',
                    'delimiter': '',
                    'operator': QueryObservationConditionOperator.EQUALS,
                    'observation_date_inverted': False,
                    'observation_date_value_type': None,
                    'observation_date_value': None,
                    'create_assay_limited_addable_column': False,
                    'protocols': None,
                    'units': None,
                    'concentrations': None,
                    'concentration_units': None,
                    'related_column_conditions': []
                }
            ]
        }  # yapf: disable
        query_obj = Query.from_dict(query_def)
        self.assertDictEqual(query_def, query_obj.as_dict())
        self.assertIsInstance(query_obj.conditions[0], QueryStructureCondition)
        self.assertIsInstance(query_obj.conditions[1], QueryRangedObservationCondition)
        self.assertIsInstance(query_obj.conditions[2], QueryObservationCondition)
        self.assertIsInstance(query_obj.conditions[3], QueryObservationCondition)
        self.assertIsInstance(query_obj.conditions[4], QueryLiveReportCondition)
        self.assertIsInstance(query_obj.conditions[5], QueryProjectCondition)
        self.assertIsInstance(query_obj.conditions[6], QueryRangedObservationCondition)
        self.assertIsInstance(query_obj.conditions[7], QueryDateRangeObservationCondition)
        self.assertIsInstance(query_obj.conditions[8], QueryRelativeDateObservationCondition)


if __name__ == "__main__":
    nose.run(argv=["", "experimental_ldclient_unit_tests", "-s", "--verbosity=2"])
