from dataclasses import replace
from tika import parser
import utils
import json
from datetime import datetime
import pandas as pd

pd.set_option('display.max_columns', None)
pd.set_option('display.width', None)


def get_meta_indices(alist):
    for index, item in enumerate(alist):
        if "AUSFAHRLISTE" in item:
            return [i for i in range(index, len(alist))]


class Ausfahrliste:
    """
    Separation of customer  info is based on the fact that each
    customer has a number. If you look keenly after splitting
    the extracted pdf, you'll find that customer numbers are not
    preceded by any space while other numbers are (apart from
    plz or regional code). Thus, we are taking advantage of these
    two facts to separate customers.

    Assumption:
    There is no way number of
    customers are going to be more than 1000 so the region code
    can never be a customer number.
    """

    def __init__(self, afile):
        self.afile = afile
        self.table = None

    def read_pdf(self):
        return parser.from_file(self.afile)

    def get_content(self):
        contents = self.read_pdf()["content"]
        contents = utils.replace_unreasonable_text(text=contents, text2replace="76356 in Eimer legen", replacer_text="in Eimer legen\n76356 Weingarten")
        return contents

    def create_reasonable_pdf_text_splits(self):
        return self.get_content().split("\n")

    def get_indices_of_customer_numbers(self):
        """
        Here we are taking advantage of the fact that
        a customer number has no preceding space in the string.
        :return: list

        """
        customer_line_indices = []
        for index, line in enumerate(self.create_reasonable_pdf_text_splits()):
            line_splits = line.split(" ")
            if utils.is_comma(line_splits):  # Every customer line must have a comma
                if len(line_splits) > 0:  # This ensures all blank items are removed
                    try:
                        int(line_splits[0])  # we are looking for an integer
                        if len(line_splits[0]) < 5:  # Region code should not be the first customer line
                            customer_line_indices.append(index)
                    except ValueError:
                        ""
        return customer_line_indices

    def create_index_spans_for_customers(self):
        """
        We take advantage of the preceding function where
        we create customer indices to create spans of
        indices
        :return: dictionary
        """
        indices = self.get_indices_of_customer_numbers()
        customer_spans = {}
        for index, _ in enumerate(indices):
            if index < len(indices) - 1:
                customer_spans[f'customer_no {index + 1}'] = [i for i in range(indices[index], indices[index + 1])]
            else:
                customer_spans[f'customer_no {index + 1}'] = [i for i in
                                                              range(indices[index],
                                                                    len(self.create_reasonable_pdf_text_splits()))]  # from the last index containing customer no to the end of the document

        return customer_spans

    def get_actual_customer_data_using_indices(self):
        """
        using the indices in the preceding function, let us get customer
        data
        :return: dictionary
        """
        customer_indices_dict = self.create_index_spans_for_customers()
        mixed_customer_data = self.create_reasonable_pdf_text_splits()
        customer_data_dict = customer_indices_dict
        for key in customer_indices_dict:
            single_customer_indices = customer_indices_dict[key]
            customer_data_dict[key] = [mixed_customer_data[i] for i in single_customer_indices]
            # if key == "customer_no 6" or key == "customer_no 7" or key == "customer_no 10":
            #     print_json(customer_data_dict[key])
        return customer_data_dict

    def get_meta_info(self):
        whole_document_list = self.create_reasonable_pdf_text_splits()
        whole_document_list = [i for i in whole_document_list if i != ""]
        meta_dict = {}
        for index, item in enumerate(whole_document_list):
            splits = item.split(" ")
            if "Route" in splits:
                for sub_index, sub_item in enumerate(splits):
                    if "." in sub_item:
                        meta_dict["date"] = datetime.strftime(datetime.strptime(sub_item, "%d.%m.%y"), "%Y-%m-%d")
                    if "Seite" in sub_item:
                        meta_dict["page"] = splits[sub_index + 1]
                    if "Route" in sub_item:
                        meta_dict["route"] = splits[sub_index - 1]
            if "eigene" in splits:
                for sub_index, sub_item in enumerate(splits):
                    if "." in sub_item:
                        meta_dict["date"] = datetime.strftime(datetime.strptime(sub_item, "%d.%m.%y"), "%Y-%m-%d")
                    if "Seite" in sub_item:
                        meta_dict["page"] = splits[sub_index + 1]
            if "Tour:" in splits:
                for sub_index, sub_item in enumerate(splits):
                    if sub_item == "Tour:":
                        meta_dict["tour"] = splits[sub_index + 1]
                    if sub_item == "Logistikpartner:":
                        meta_dict["logistikpartner"] = utils.list2string(
                            [splits[i] for i in [sub_index + 1, sub_index + 2]])
                    if sub_item == "km":
                        meta_dict["short distance"] = splits[sub_index - 1]
                        try:
                            long_route = splits[sub_index + 1]
                            meta_dict["long route"] = utils.remove_brackets(long_route)
                        except IndexError:
                            meta_dict["long distance"] = ""
            if "Kommissionierzone:" in splits:
                meta_dict["bakery"] = utils.list2string(splits[1:])
        return meta_dict

    def get_list_of_breads_for_this_ausfahrliste(self):
        breads = []
        customer_dict = self.get_actual_customer_data_using_indices()
        for key in customer_dict:
            bread_dict = utils.get_breads(customer_dict[key])
            specific_customer_breads = [i for i in bread_dict.keys()]
            for bread in specific_customer_breads:
                if bread not in breads:
                    breads.append(bread)
        return sorted(breads)

    def make_customer_table(self):
        all_breads = self.get_list_of_breads_for_this_ausfahrliste()
        customer_dict = self.get_actual_customer_data_using_indices()
        dict_list = []
        for key in customer_dict:
            customer_no = key.split(" ")[1]
            alist = customer_dict[key]
            customer_name = utils.get_customer_name(alist)
            customer_partial_address = utils.get_customer_partial_address(alist)
            customer_status = utils.get_customer_status(alist)
            customer_plz = utils.get_region_plz(alist)
            customer_address = f'{customer_partial_address}{customer_plz}'
            customer_instructions = utils.get_additional_customer_information(alist)
            customer_info_as_dict = {
                "no": customer_no,
                "name": customer_name,
                "address": customer_address,
                "status": customer_status,
                "instructions": customer_instructions
            }
            bread_dict = utils.get_breads(alist)
            for bread in all_breads:
                if bread in bread_dict:
                    customer_info_as_dict[bread] = bread_dict[bread]
                else:
                    customer_info_as_dict[bread] = 0
            dict_list.append(pd.DataFrame(customer_info_as_dict, index=[0]))
        df = pd.concat(dict_list)
        df.index = [i for i in df["no"]]
        df.drop("no", axis=1, inplace=True)
        return df

    def get_clean_table(self):
        table = self.make_customer_table()
        status = [i for i in table["status"]]
        instructions = [i for i in table["instructions"]]
        count = 0
        for statu, instru in zip(status, instructions):
            statu = statu.strip()
            if statu == "TRG" or statu == "RKL" or statu == "PRO" or statu == "NEU":
                instructions[count] = instru.split(statu)[1]
            count += 1
        table["instructions"] = instructions
        self.table = table

    def add_totals_to_customer_table(self):
        self.get_clean_table()
        table = self.table
        bread_table = table.drop(["name", "address", "status", "instructions"], axis=1)
        bread_table = bread_table.astype(int)
        table["total"] = bread_table.sum(axis=1)
        self.table = table

    def breads_count_numeric(self):
        self.get_clean_table()
        self.add_totals_to_customer_table()
        bread_table = self.table.drop(["name", "address", "status", "instructions"], axis=1)
        flatten = [int(i) for i in bread_table.values.flatten()]
        return int(sum(flatten) / 2)

    def add_meta_to_table(self):
        self.breads_count_numeric()
        meta = self.get_meta_info()
        self.table.insert(0, "customer_no", '')
        self.table["customer_no"] = self.table.index
        self.table.insert(2, "date", '')
        self.table["date"] = datetime.strftime(datetime.strptime(meta["date"], "%Y-%m-%d"), "%d.%m.%y")

    def rename_columns(self):
        self.add_meta_to_table()
        self.table.rename(columns={"name": "customer_name",
                                   "address": "customer_address",
                                   "status": "customer_status",
                                   "instructions": "additional_info"},
                          errors="raise",
                          inplace=True)


if __name__ == "__main__":
    # afile = "/home/joseph/personal_folder/fahrer_minijob/delivery_files/2021-12-16_ausfahrliste_delivery_file.pdf"
    afile = "/home/joseph/Downloads/Akbar_02Jan2022.pdf"
    afile = "delivery_files/2021-02-07_ausfahrliste_delivery_file.pdf"


    def print_json(x):
        print(json.dumps(x, indent=4))


    obj = Ausfahrliste(afile)
    # print(utils.replace_unreasonable_text(text = obj.get_content(), text2replace="in Eimer legen",
    # replacer_text="Weingarten"))
    #print(obj.get_content())

    """
    Next steps:
    1. Get distances
    2. Summarize each day into a file
    3. Create one large file for all deliveries ever made    
    """
    print(obj.get_list_of_breads_for_this_ausfahrliste())
from dataclasses import replace
from tika import parser
import utils
import json
from datetime import datetime
import pandas as pd

pd.set_option('display.max_columns', None)
pd.set_option('display.width', None)


def get_meta_indices(alist):
    for index, item in enumerate(alist):
        if "AUSFAHRLISTE" in item:
            return [i for i in range(index, len(alist))]


class Ausfahrliste:
    """
    Separation of customer  info is based on the fact that each
    customer has a number. If you look keenly after splitting
    the extracted pdf, you'll find that customer numbers are not
    preceded by any space while other numbers are (apart from
    plz or regional code). Thus, we are taking advantage of these
    two facts to separate customers.

    Assumption:
    There is no way number of
    customers are going to be more than 1000 so the region code
    can never be a customer number.
    """

    def __init__(self, afile):
        self.afile = afile
        self.table = None

    def read_pdf(self):
        return parser.from_file(self.afile)

    def get_content(self):
        contents = self.read_pdf()["content"]
        contents = utils.replace_unreasonable_text(text=contents, text2replace="76356 in Eimer legen", replacer_text="in Eimer legen\n76356 Weingarten")
        return contents

    def create_reasonable_pdf_text_splits(self):
        return self.get_content().split("\n")

    def get_indices_of_customer_numbers(self):
        """
        Here we are taking advantage of the fact that
        a customer number has no preceding space in the string.
        :return: list

        """
        customer_line_indices = []
        for index, line in enumerate(self.create_reasonable_pdf_text_splits()):
            line_splits = line.split(" ")
            if utils.is_comma(line_splits):  # Every customer line must have a comma
                if len(line_splits) > 0:  # This ensures all blank items are removed
                    try:
                        int(line_splits[0])  # we are looking for an integer
                        if len(line_splits[0]) < 5:  # Region code should not be the first customer line
                            customer_line_indices.append(index)
                    except ValueError:
                        ""
        return customer_line_indices

    def create_index_spans_for_customers(self):
        """
        We take advantage of the preceding function where
        we create customer indices to create spans of
        indices
        :return: dictionary
        """
        indices = self.get_indices_of_customer_numbers()
        customer_spans = {}
        for index, _ in enumerate(indices):
            if index < len(indices) - 1:
                customer_spans[f'customer_no {index + 1}'] = [i for i in range(indices[index], indices[index + 1])]
            else:
                customer_spans[f'customer_no {index + 1}'] = [i for i in
                                                              range(indices[index],
                                                                    len(self.create_reasonable_pdf_text_splits()))]  # from the last index containing customer no to the end of the document

        return customer_spans

    def get_actual_customer_data_using_indices(self):
        """
        using the indices in the preceding function, let us get customer
        data
        :return: dictionary
        """
        customer_indices_dict = self.create_index_spans_for_customers()
        mixed_customer_data = self.create_reasonable_pdf_text_splits()
        customer_data_dict = customer_indices_dict
        for key in customer_indices_dict:
            single_customer_indices = customer_indices_dict[key]
            customer_data_dict[key] = [mixed_customer_data[i] for i in single_customer_indices]
            # if key == "customer_no 6" or key == "customer_no 7" or key == "customer_no 10":
            #     print_json(customer_data_dict[key])
        return customer_data_dict

    def get_meta_info(self):
        whole_document_list = self.create_reasonable_pdf_text_splits()
        whole_document_list = [i for i in whole_document_list if i != ""]
        meta_dict = {}
        for index, item in enumerate(whole_document_list):
            splits = item.split(" ")
            if "Route" in splits:
                for sub_index, sub_item in enumerate(splits):
                    if "." in sub_item:
                        meta_dict["date"] = datetime.strftime(datetime.strptime(sub_item, "%d.%m.%y"), "%Y-%m-%d")
                    if "Seite" in sub_item:
                        meta_dict["page"] = splits[sub_index + 1]
                    if "Route" in sub_item:
                        meta_dict["route"] = splits[sub_index - 1]
            if "eigene" in splits:
                for sub_index, sub_item in enumerate(splits):
                    if "." in sub_item:
                        meta_dict["date"] = datetime.strftime(datetime.strptime(sub_item, "%d.%m.%y"), "%Y-%m-%d")
                    if "Seite" in sub_item:
                        meta_dict["page"] = splits[sub_index + 1]
            if "Tour:" in splits:
                for sub_index, sub_item in enumerate(splits):
                    if sub_item == "Tour:":
                        meta_dict["tour"] = splits[sub_index + 1]
                    if sub_item == "Logistikpartner:":
                        meta_dict["logistikpartner"] = utils.list2string(
                            [splits[i] for i in [sub_index + 1, sub_index + 2]])
                    if sub_item == "km":
                        meta_dict["short distance"] = splits[sub_index - 1]
                        try:
                            long_route = splits[sub_index + 1]
                            meta_dict["long route"] = utils.remove_brackets(long_route)
                        except IndexError:
                            meta_dict["long distance"] = ""
            if "Kommissionierzone:" in splits:
                meta_dict["bakery"] = utils.list2string(splits[1:])
        return meta_dict

    def get_list_of_breads_for_this_ausfahrliste(self):
        breads = []
        customer_dict = self.get_actual_customer_data_using_indices()
        for key in customer_dict:
            bread_dict = utils.get_breads(customer_dict[key])
            specific_customer_breads = [i for i in bread_dict.keys()]
            for bread in specific_customer_breads:
                if bread not in breads:
                    breads.append(bread)
        return sorted(breads)

    def make_customer_table(self):
        all_breads = self.get_list_of_breads_for_this_ausfahrliste()
        customer_dict = self.get_actual_customer_data_using_indices()
        dict_list = []
        for key in customer_dict:
            customer_no = key.split(" ")[1]
            alist = customer_dict[key]
            customer_name = utils.get_customer_name(alist)
            customer_partial_address = utils.get_customer_partial_address(alist)
            customer_status = utils.get_customer_status(alist)
            customer_plz = utils.get_region_plz(alist)
            customer_address = f'{customer_partial_address}{customer_plz}'
            customer_instructions = utils.get_additional_customer_information(alist)
            customer_info_as_dict = {
                "no": customer_no,
                "name": customer_name,
                "address": customer_address,
                "status": customer_status,
                "instructions": customer_instructions
            }
            bread_dict = utils.get_breads(alist)
            for bread in all_breads:
                if bread in bread_dict:
                    customer_info_as_dict[bread] = bread_dict[bread]
                else:
                    customer_info_as_dict[bread] = 0
            dict_list.append(pd.DataFrame(customer_info_as_dict, index=[0]))
        df = pd.concat(dict_list)
        df.index = [i for i in df["no"]]
        df.drop("no", axis=1, inplace=True)
        return df

    def get_clean_table(self):
        table = self.make_customer_table()
        status = [i for i in table["status"]]
        instructions = [i for i in table["instructions"]]
        count = 0
        for statu, instru in zip(status, instructions):
            statu = statu.strip()
            if statu == "TRG" or statu == "RKL" or statu == "PRO" or statu == "NEU":
                instructions[count] = instru.split(statu)[1]
            count += 1
        table["instructions"] = instructions
        self.table = table

    def add_totals_to_customer_table(self):
        self.get_clean_table()
        table = self.table
        bread_table = table.drop(["name", "address", "status", "instructions"], axis=1)
        bread_table = bread_table.astype(int)
        table["total"] = bread_table.sum(axis=1)
        self.table = table

    def breads_count_numeric(self):
        self.get_clean_table()
        self.add_totals_to_customer_table()
        bread_table = self.table.drop(["name", "address", "status", "instructions"], axis=1)
        flatten = [int(i) for i in bread_table.values.flatten()]
        return int(sum(flatten) / 2)

    def add_meta_to_table(self):
        self.breads_count_numeric()
        meta = self.get_meta_info()
        self.table.insert(0, "customer_no", '')
        self.table["customer_no"] = self.table.index
        self.table.insert(2, "date", '')
        self.table["date"] = datetime.strftime(datetime.strptime(meta["date"], "%Y-%m-%d"), "%d.%m.%y")

    def rename_columns(self):
        self.add_meta_to_table()
        self.table.rename(columns={"name": "customer_name",
                                   "address": "customer_address",
                                   "status": "customer_status",
                                   "instructions": "additional_info"},
                          errors="raise",
                          inplace=True)


if __name__ == "__main__":
    # afile = "/home/joseph/personal_folder/fahrer_minijob/delivery_files/2021-12-16_ausfahrliste_delivery_file.pdf"
    afile = "/home/joseph/Downloads/Akbar_02Jan2022.pdf"
    afile = "delivery_files/2021-02-07_ausfahrliste_delivery_file.pdf"


    def print_json(x):
        print(json.dumps(x, indent=4))


    obj = Ausfahrliste(afile)
    # print(utils.replace_unreasonable_text(text = obj.get_content(), text2replace="in Eimer legen",
    # replacer_text="Weingarten"))
    #print(obj.get_content())

    """
    Next steps:
    1. Get distances
    2. Summarize each day into a file
    3. Create one large file for all deliveries ever made    
    """
    print(obj.get_list_of_breads_for_this_ausfahrliste())
Separation of customer  info is based on the fact that each     customer has a number. If you look keenly after splitting     the extracted pdf, you'll find that customer numbers are not     preceded by any space while other numbers are (apart from     plz or regional code). Thus, we are taking advantage of these     two facts to separate customers.      Assumption:     There is no way number of     customers are going to be more than 1000 so the region code     can never be a customer number. Here we are taking advantage of the fact that         a customer number has no preceding space in the string.         :return: list # Every customer line must have a comma # This ensures all blank items are removed # we are looking for an integer # Region code should not be the first customer line We take advantage of the preceding function where         we create customer indices to create spans of         indices         :return: dictionary # from the last index containing customer no to the end of the document using the indices in the preceding function, let us get customer         data         :return: dictionary # if key == "customer_no 6" or key == "customer_no 7" or key == "customer_no 10": #     print_json(customer_data_dict[key]) # afile = "/home/joseph/personal_folder/fahrer_minijob/delivery_files/2021-12-16_ausfahrliste_delivery_file.pdf" # print(utils.replace_unreasonable_text(text = obj.get_content(), text2replace="in Eimer legen", # replacer_text="Weingarten")) #print(obj.get_content()) Next steps:     1. Get distances     2. Summarize each day into a file     3. Create one large file for all deliveries ever made