import csv
import typing
from os import path

from pycs.interfaces.LabelProvider import LabelProvider


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

    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(lambda row: {
                'localOccurence': self.__replace_empty_with_none(row[0]),
                'rarity': self.__replace_empty_with_none(row[1]),
                'superfamily': self.__replace_empty_with_none(row[2]),
                'family': self.__replace_empty_with_none(row[3]),
                'subfamily': self.__replace_empty_with_none(row[4]),
                'tribe': self.__replace_empty_with_none(row[5]),
                'krNumber': self.__replace_empty_with_none(row[9]),
                'genus': self.__replace_empty_with_none(row[10]),
                'species': self.__replace_empty_with_none(row[11])
            }, reader))

        # filter
        if self.csv_minimum_rarity is not None:
            def flt_fn(e):
                r = e['rarity']
                return r is not None and r.isnumeric() and self.csv_minimum_rarity < int(r)

            entries = list(filter(flt_fn, entries))

        # create result set
        for entry in entries:
            parent_reference = None

            # add hierarchy
            for tax in ('superfamily', 'family', 'subfamily', 'tribe'):
                if entry[tax] is not None:
                    reference, name = entry[tax].lower(), entry[tax]
                    result.append(self.create_label(reference, name, parent_reference))

                    parent_reference = reference

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

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

        return result

    @staticmethod
    def __replace_empty_with_none(val: str):
        return val if val.strip() else None
