#   Copyright ETH 2018 - 2024 Zürich, Scientific IT Services
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#
import random

import time
import uuid


def test_create_delete_vocabulary(openbis_instance):
    o = openbis_instance
    timestamp = time.strftime('%a_%y%m%d_%H%M%S').upper()
    voc_code = 'test_voc_' + timestamp + "_" + str(random.randint(0, 1000))

    voc = o.new_vocabulary(
        code=voc_code,
        description='description of vocabulary',
        urlTemplate='https://ethz.ch',
        terms=[
            {"code": 'term_code1', "label": "term_label1", "description": "term_description1"},
            {"code": 'term_code2', "label": "term_label2", "description": "term_description2"},
            {"code": 'term_code3', "label": "term_label3", "description": "term_description3"}
        ],
        chosenFromList=False
    )
    assert voc.registrationDate is None
    voc.save()
    assert voc is not None
    assert voc.registrationDate is not None
    assert voc.chosenFromList is False

    voc_exists = o.get_vocabulary(voc_code)
    assert voc_exists is not None
    assert voc_exists.code == voc_code.upper()

    voc.description = 'description changed'
    voc.chosenFromList = True
    voc.save()

    assert voc.description == 'description changed'
    assert voc.chosenFromList is True

    voc.delete('test on ' + str(timestamp))


def test_create_vocabulary_and_delete_term(openbis_instance):
    o = openbis_instance
    timestamp = time.strftime('%a_%y%m%d_%H%M%S').upper()
    voc_code = 'test_voc_' + timestamp + "_" + str(random.randint(0, 1000))

    voc = o.new_vocabulary(
        code=voc_code,
        description='description of vocabulary',
        urlTemplate='https://ethz.ch',
        terms=[
            {"code": 'term_code1', "label": "term_label1", "description": "term_description1"},
            {"code": 'term_code2', "label": "term_label2", "description": "term_description2"},
            {"code": 'term_code3', "label": "term_label3", "description": "term_description3"}
        ],
        chosenFromList=False
    )
    assert voc.registrationDate is None
    voc.save()
    assert voc is not None
    assert voc.registrationDate is not None
    assert voc.chosenFromList is False

    term = o.get_term('term_code3'.upper(), voc_code.upper())
    term.delete('some_reason')

    saved_vocab = o.get_vocabulary(voc_code.upper())
    terms = saved_vocab.get_terms()
    assert list(terms.df['code']) == ['TERM_CODE1', 'TERM_CODE2']


def test_create_set_and_remove_vocabulary_property(space):
    o = space.openbis
    timestamp = time.strftime('%a_%y%m%d_%H%M%S').upper()
    voc_code = 'test_voc_' + timestamp + "_" + str(random.randint(0, 1000))

    voc = o.new_vocabulary(
        code=voc_code,
        description='description of vocabulary',
        urlTemplate='https://ethz.ch',
        terms=[
            {"code": 'term_code1', "label": "term_label1", "description": "term_description1"},
            {"code": 'term_code2', "label": "term_label2", "description": "term_description2"},
            {"code": 'term_code3', "label": "term_label3", "description": "term_description3"}
        ],
        chosenFromList=False
    )
    voc.save()

    voc_exists = o.get_vocabulary(voc_code)
    assert voc_exists is not None
    assert voc_exists.code == voc_code.upper()

    property_type_code = "test_vocabulary_property_type_" + timestamp + "_" + str(uuid.uuid4())
    pt_date = o.new_property_type(
        code=property_type_code,
        label='custom property of data type controlled vocabulary',
        description='custom property created in unit test',
        dataType='CONTROLLEDVOCABULARY',
        vocabulary=voc_code
    )
    pt_date.save()

    # Create custom sample type
    sample_type_code = "test_sample_type_" + timestamp + "_" + str(uuid.uuid4())
    sample_type = o.new_sample_type(
        code=sample_type_code,
        generatedCodePrefix="S",
        autoGeneratedCode=True,
        listable=True,
    )
    sample_type.save()

    # Assign created property to new sample type
    sample_type.assign_property(
        prop=property_type_code,
        section='vocabulary section',
        ordinal=1,
        mandatory=False,
        showInEditView=True,
        showRawValueInForms=True
    )

    project = space.new_project(f'my_project_{timestamp}')
    project.save()

    collection = o.new_experiment('UNKNOWN', f'my_collection_{timestamp}', project)
    collection.save()

    sample_code = "my_sample_{}".format(timestamp)

    sample = space.new_sample(code=sample_code,
                              type=sample_type_code,
                              experiment=collection,
                              props={
                                  property_type_code.lower(): 'term_code1'})
    sample.save()

    assert len(sample.props()) == 1
    key, val = sample.props().popitem()
    assert key.lower() == property_type_code.lower()
    assert val == 'term_code1'.upper()

    sample.props[property_type_code.lower()] = None
    sample.save()

    assert len(sample.props()) == 1
    key, val = sample.props().popitem()
    assert key.lower() == property_type_code.lower()
    assert val is None


def test_create_delete_vocabulary_term(openbis_instance):
    o = openbis_instance
    timestamp = time.strftime('%a_%y%m%d_%H%M%S').upper()
    voc_code = 'test_voc_' + timestamp + "_" + str(random.randint(0, 1000))

    voc = o.new_vocabulary(
        code=voc_code,
        description='description of vocabulary',
        urlTemplate='https://ethz.ch',
        terms=[
            {"code": 'term_code1', "label": "term_label1", "description": "term_description1"},
            {"code": 'term_code2', "label": "term_label2", "description": "term_description2"},
            {"code": 'term_code3', "label": "term_label3", "description": "term_description3"}
        ],
        chosenFromList=False
    )
    assert voc.registrationDate is None
    voc.save()
    assert voc is not None
    assert voc.registrationDate is not None
    assert voc.chosenFromList is False

    voc_exists = o.get_vocabulary(voc_code)
    assert voc_exists is not None
    assert voc_exists.code == voc_code.upper()

    # Create vocabulary term
    voc_term = o.new_term('term_code4', voc_code.upper(), 'term_label4', 'term_description4')
    voc_term.save()

    assert voc_term is not None
    assert voc_term.registrationDate is not None
    voc_terms = o.get_terms(voc_code, use_cache=False)
    assert len(voc_terms) == 4

    # Delete vocabulary term
    voc_term.delete('some test reason')

    voc_terms = o.get_terms(voc_code, use_cache=False)
    assert len(voc_terms) == 3

