import csv
import typing
from os import path

from pycs.interfaces.LabelProvider import LabelProvider
from .RowWrapper import RowWrapper


class Provider(LabelProvider):
    def __init__(self, root_folder, configuration):
        self.csv_path = path.join(root_folder, configuration['filename'])
        self.csv_minimum_rarity = configuration['minimumRarity']
        self.csv_all_hierarchy_levels = configuration['includeAllHierarchyLevels']

    def close(self):
        pass

    def get_labels(self) -> typing.List[dict]:
        result = []

        with open(self.csv_path, mode='r', newline='', encoding='utf8') as csv_file:
            # skip first line which contains column names
            csv_file.readline()

            # read csv line by line
            reader = csv.reader(csv_file, delimiter='\t')
            entries = list(map(RowWrapper, reader))

        # filter
        if self.csv_minimum_rarity is not None:
            entries = filter(lambda row: row.rarity_is_larger_than(self.csv_minimum_rarity),
                             entries)

        # create result set
        if self.csv_all_hierarchy_levels:
            hierarchy_levels = (('superfamily', 'Überfamilie'),
                                ('family', 'Familie'),
                                ('subfamily', 'Unterfamilie'),
                                ('tribe', 'Tribus'),
                                ('genus', 'Gattung'))
        else:
            hierarchy_levels = (('family', 'Familie'),
                                ('genus', 'Gattung'))

        parents = set()
        for entry in entries:
            entry = entry.__dict__
            parent_reference = None

            # add hierarchy
            for level, level_name in hierarchy_levels:
                if entry[level] is not None:
                    reference, name = f'{level}_{entry[level].lower()}', entry[level]

                    # parents should be added once
                    if reference not in parents:
                        result.append(self.create_label(reference, name, parent_reference, level_name))
                        parents.add(reference)

                    parent_reference = reference

            # add element
            if entry['kr_number'].isalnum():
                name = f'{entry["genus"]} {entry["species"]} ({entry["kr_number"]})'
                reference = entry['kr_number']
            else:
                name = f'{entry["genus"]} {entry["species"]}'
                reference = f'_{name.lower()}'

            result.append(self.create_label(reference, name, parent_reference))

        return result
