#!/usr/bin/env python

import codecs
import csv
from ftplib import FTP
import logging.config
import os
import shutil
import time

def setup_logging(log_path):
    # Set up logging
    log_file = os.path.join(log_path, '{}.log'.format(time.strftime("%Y%m%d-%H%M%S")))

    logging.config.dictConfig({
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'standard': {
                'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
            },
        },
        'handlers': {
            'default': {
                'level': 'NOTSET',
                'class': 'logging.StreamHandler',
                'formatter': 'standard'
            },
            'logfile': {
                'filename': log_file,
                'class': 'logging.FileHandler',
                'formatter': 'standard'
            }
        },
        'loggers': {
            '': {
                'handlers': ['default', 'logfile'],
                'level': 'NOTSET',
                'propagate': True
            }
        }
    })


def get_files_from_ftp(in_path):
    filenames = ["inventory.csv", "items.csv"]

    try:
        logging.debug("Retrieving files from Atixo...")
        ftp = FTP(host="atixo.de", user="atixo", passwd="atixo_wholesale")

        for filename in filenames:
            full_path = os.path.join(in_path, filename)
            with open(full_path, "wb") as f:
                ftp.retrbinary('RETR ' + filename, f.write, 1024)

        ftp.quit()
    except Exception as ex:
        logging.error(ex)

def read_ref(ref_path):
    ref_dict = {}

    header_read = False
    barcode_index = -1
    ean_index = -1
    full_ref_path = os.path.join(ref_path, "GS1 EAN Liste für alte Artikel.csv")
    with codecs.open(full_ref_path, "rb", encoding='utf-8') as f:

        reader = csv.reader(f, delimiter=';')
        for row in reader:
            if header_read:
                ref_dict[row[barcode_index]] = row[ean_index]
            else:
                barcode_index = row.index("EAN")
                ean_index = row.index("EAN2")
                header_read = True

    return ref_dict


def read_item_availability(file_path):
    item_avail_dict = dict()

    header_read = False
    item_idx = -1
    avail_idx = -1

    with codecs.open(file_path, "rb", encoding='cp1252') as f:

        reader = csv.reader(f, delimiter=';')
        for row in reader:
            if header_read:
                item_id = row[item_idx].strip()
                item_avail = row[avail_idx].strip()

                if item_id in item_avail_dict:
                    msg = "Duplicate Item Id : {}".format(item_id)
                    print(msg)
                    logging.error(msg)
                else:
                    item_avail_dict[item_id] = item_avail
            else:
                item_idx = row.index("Artikel-Nr.")
                avail_idx = row.index("Verfügbarkeit")

                if avail_idx < 0 or item_idx < 0:
                    raise Exception("Missing columns in availability file")

                header_read = True

    return item_avail_dict


def convert_file(in_file, out_file, item_avail_dict, ref_dict):
    header_read = False
    item_id_index = 0
    last_col_blank = False
    new_row = []
    barcode_index = -1

    with codecs.open(in_file, "r", encoding='cp1252') as f, \
        codecs.open(out_file, "w", encoding='utf-8') as of:
        reader = csv.reader(f, delimiter=';')
        writer = csv.writer(of, delimiter=';', quoting=csv.QUOTE_NONNUMERIC)

        for row in reader:
            if header_read:
                item_id = row[item_id_index]
                barcode = row[barcode_index]

                if  barcode[:6] == "250000":
                    if barcode in ref_dict:
                        row[barcode_index] = ref_dict[barcode]
                    else:
                        print("Could not find barcode {} in ref". format(barcode))
                        continue

                if item_id in item_avail_dict:
                    if last_col_blank:
                        new_row = row
                        new_row[-1] = item_avail_dict[item_id]
                    else:
                        new_row = row + [item_avail_dict[item_id]]
                else:
                    if last_col_blank:
                        new_row = row
                        new_row[-1] = "No"
                    else:
                        new_row = row + ["No"]
            else:
                header_read = True

                if row[-1] == "":
                    last_col_blank = True
                    new_row = row
                    new_row[-1] = "Verfügbar"
                else:
                    new_row = row + ["Verfügbar"]

                if "Barcode" in row:
                    barcode_index = row.index("Barcode")

                if barcode_index < 0:
                    raise Exception("barcode column not found. Aborting.")

            writer.writerow(new_row)

def process(data_root):
    path_ref = os.path.join(data_root, "ref")
    path_in = os.path.join(data_root, "in")
    path_out = os.path.join(data_root, "out")
    path_proc = os.path.join(data_root, "processed")
    path_err = os.path.join(data_root, "error")
    path_log = os.path.join(data_root, "log")

    setup_logging(path_log)

    get_files_from_ftp(path_in)

    files = os.listdir(path_in)
    num_files = len(files)

    logging.debug("Found {0} files...".format(num_files))

    if num_files == 0:
        return

    item_file = "items.csv"
    item_avail_file = "inventory.csv"

    full_item_path = os.path.join(path_in, item_file)
    full_item_avail_path = os.path.join(path_in, item_avail_file)
    out_file_path = os.path.join(path_out, item_file)

    if os.path.exists(full_item_path) and os.path.exists(full_item_avail_path):
        ref_dict = read_ref(path_ref)
        item_avail_dict = read_item_availability(full_item_avail_path)

        try:
            print("Converting {0} to {1}...".format(full_item_path, out_file_path))

            convert_file(full_item_path, out_file_path, item_avail_dict, ref_dict)

            # Move to processed
            shutil.move(full_item_path, os.path.join(path_proc, item_file))
            shutil.move(full_item_avail_path, os.path.join(path_proc, item_avail_file))
        except Exception as e:
            logging.error(e)

            # Move to error
            shutil.move(full_item_path, os.path.join(path_err, item_file))
            shutil.move(full_item_avail_path, os.path.join(path_err, item_avail_file))

            if os.path.exists(out_file_path):
                os.remove(out_file_path)
    else:
        logging.error("Cannot find {} and/or {}".format(item_file, item_avail_file))


def main():
    # data_root = r"/home/holger/git/bitbucket/thelen/data/"
    data_root = r"/ftproot/"

    project_data_root = os.path.join(data_root, "Matching_Atixo_Bestand")

    process(project_data_root)

    print("Done.")


if __name__ == "__main__":
    main()
