import pathlib
import csv
from typing import OrderedDict


def read_csv_file_with_header_to_hashed_odict_of_odicts(path_csv_file: pathlib.Path,
                                                        hash_by_fieldname: str,
                                                        encoding: str = "ISO-8859-1",
                                                        delimiter: str = ";",
                                                        quotechar: str = '"',
                                                        quoting: int = csv.QUOTE_MINIMAL) -> 'OrderedDict[str, OrderedDict[str, str]]':
    """
    reads the csv file into an ordered dict of ordered dicts
    returns: {'indexfield':{fieldname1:value, fieldname2:value}, 'indexfield2':{fieldname1:value, fieldname2:value}}

    >>> # setup
    >>> test_directory = pathlib.Path(__file__).absolute().parent.parent / 'tests'
    >>> testfile1 = test_directory / '2018-04-26_alle_Navision_Artikel.csv'
    >>> testfile2 = test_directory / '0001_aktive_preis_qty.csv'
    >>> csv_file_broken_less_fields_than_header = test_directory / 'csv_file_broken_less_fields_than_header.csv'
    >>> r_csv = read_csv_file_with_header_to_hashed_odict_of_odicts

    >>> # Test Fieldname for hashing not existent in the header
    >>> r_csv(path_csv_file=testfile1, hash_by_fieldname='not_existing') # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
    Traceback (most recent call last):
    ...
    ValueError: Field "not_existing" is not available, or the csv file does not have header information

    >>> # Test OK, Fieldname for hashing is unique
    >>> r_csv(path_csv_file=testfile1, hash_by_fieldname='Nr.') # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
    OrderedDict([('HUB025', OrderedDict([('HTMLpublish', 'Nein'), ('Artikel Nicht Verfügbar', 'Nein'), ('Sperre Angebot', 'Nein'), ...

    >>> # Test Fieldname for hashing is not unique
    >>> r_csv(path_csv_file=testfile2, hash_by_fieldname='CustomLabel')  # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
    Traceback (most recent call last):
    ...
    ValueError: Index is not unique, field: "CustomLabel", value: "HUB179"

    >>> # Test Number of Fields is smaller than the header
    >>> r_csv(path_csv_file=csv_file_broken_less_fields_than_header, hash_by_fieldname='a')  # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
    Traceback (most recent call last):
    ...
    ValueError: Row has length 3 instead of 4 : "['1', '2', '3']"



    """
    with open(str(path_csv_file), 'r', encoding=encoding) as f_csv_file:
        is_first_row = True
        fieldnames = []
        index_of_hash_field = 0
        number_of_rows = 0
        dict_result = OrderedDict()

        my_csv_reader = csv.reader(f_csv_file, delimiter=delimiter, quotechar=quotechar, quoting=quoting)
        for row in my_csv_reader:

            if is_first_row:
                is_first_row = False
                fieldnames = row
                if hash_by_fieldname not in fieldnames:
                    raise ValueError('Field "{}" is not available, or the csv file does not have header information'.format(hash_by_fieldname))
                index_of_hash_field = fieldnames.index(hash_by_fieldname)
                number_of_rows = len(fieldnames)
                continue

            if len(row) != number_of_rows:
                raise ValueError('Row has length {} instead of {} : "{}"'.format(len(row), number_of_rows, row))

            dict_row = OrderedDict()

            for index, value in enumerate(row):
                dict_row[fieldnames[index]] = value

            index_value = row[index_of_hash_field]
            if index_value not in dict_result:
                dict_result[index_value] = dict_row
            else:
                raise ValueError('Index is not unique, field: "{}", value: "{}"'.format(hash_by_fieldname, index_value))

        return dict_result