#!/usr/bin/env python3.7

import os
import codecs
import csv
import logging
import shutil
import sys

def read_ean_lookup(ref_path):
    ref_dict = {}
    ean_idx = -1
    header_read = False

    files = os.listdir(ref_path)
    for f in files:
        full_ref_path = os.path.join(ref_path, f)
        with codecs.open(full_ref_path, "rb", encoding='utf-8') as f:
            reader = csv.reader(f, delimiter=';')

            for row in reader:
                if header_read:
                    ean = row.pop(ean_idx)
                    ean = ean.strip()

                    if ean in ref_dict:
                        logging.warning("Found duplicate EAN %s in ref.", ean)

                    ref_dict[ean] = row
                else:
                    if not "Code" in row:
                        raise Exception("Column 'Code' not found in ref.")

                    ean_idx = row.index("Code")
                    row.pop(ean_idx)
                    hdr_names = row
                    header_read = True

    return ref_dict, hdr_names

def match_eans(source_file, matched_file, unmatched_file,
    unmatched_no_dupes_file, ref_dict, headers):
    header_read = False
    ean_idx = -1

    with codecs.open(source_file, "r", encoding='utf-8') as f, \
            codecs.open(matched_file, "w", encoding='utf-8') as of, \
            codecs.open(unmatched_file, "w", encoding='utf-8') as uf, \
            codecs.open(unmatched_no_dupes_file, "w", encoding='utf-8') as df:

        reader = csv.reader(f, delimiter=';')
        writer_matched = csv.writer(of, delimiter=';',
                                    quoting=csv.QUOTE_NONNUMERIC)
        writer_unmatched = csv.writer(uf, delimiter=';',
                                      quoting=csv.QUOTE_NONNUMERIC)
        writer_unmatched_no_dupes = csv.writer(df, delimiter=';',
                                      quoting=csv.QUOTE_NONNUMERIC)
        unmatched_item_nums = []
        for row in reader:
            if header_read:
                ean = row[ean_idx].strip()
                item_num = row[0].strip()

                if ean in ref_dict:
                    writer_matched.writerow(row + ref_dict[ean])
                else:
                    writer_unmatched.writerow(row)
                    if item_num not in unmatched_item_nums:
                        writer_unmatched_no_dupes.writerow(row)
                        unmatched_item_nums.append(item_num)
            else:
                if not "EAN" in row:
                    raise Exception("Column 'EAN' not found in file '{}'"
                                    .format(source_file))
                ean_idx = row.index("EAN")

                writer_matched.writerow(row + headers)
                writer_unmatched.writerow(row)
                writer_unmatched_no_dupes.writerow(row)

                header_read = True


def process_files(data_root):
    path_in = os.path.join(data_root, "in")
    path_out = os.path.join(data_root, "out")
    path_prc = os.path.join(data_root, "processed")
    path_err = os.path.join(data_root, "error")
    path_log = os.path.join(data_root, "log")
    path_ref = os.path.join(data_root, "ref")

    files = os.listdir(path_in)
    num_files = len(files)

    print("Found {0} files...".format(num_files))
    if num_files == 0:
        return

    ean_ref, ref_headers = read_ean_lookup(path_ref)

    for f in files:
        log_filename = os.path.splitext(f)[0] + '.log'
        unmatched_filename =  "unmatched_" + f
        unmatched_no_dupes_filename =  "p_" + f

        in_file = os.path.join(path_in, f)
        out_file = os.path.join(path_out, f)
        unmatched_file = os.path.join(path_out, unmatched_filename)
        unmatched_no_dupes_file = os.path.join(path_out,
                                               unmatched_no_dupes_filename)
        prc_file = os.path.join(path_prc, f)
        err_file = os.path.join(path_err, f)
        log_file = os.path.join(path_log, log_filename)

        if os.path.isfile(in_file):
            logging.basicConfig(filename=log_file, level=logging.DEBUG)
            msg = "Matching Plenty ID Barcodes {0}...".format(in_file)
            logging.debug(msg)
            try:
                match_eans(in_file, out_file, unmatched_file,
                           unmatched_no_dupes_file, ean_ref, ref_headers)
                shutil.move(in_file, prc_file)
            except Exception as e:
                logging.error(e)
                print("Error : {}".format(e))
                shutil.move(in_file, err_file)
                sys.exit(-1)


def main():
    if os.path.exists(r"/ftproot/"):
        data_root = r"/ftproot/"
    elif os.path.exists(r"/home/holger/git/bitbucket/thelen/data/"):
        data_root = r"/home/holger/git/bitbucket/thelen/data/"
    else:
        print("Unknown environment. Please set data_root to data folder "
              "location. Aborting.")
        return


    invoice_data_root = os.path.join(data_root, "Matching_Plenty_ID_Barcode")
    process_files(invoice_data_root)

if __name__ == "__main__":
    main()
