#!/usr/bin/env python
# -*- coding: utf-8 -*-

import csv
import codecs
import logging
import os
import shutil
import sys
import time

logger = None

HEADER_REF_SKU = "sku"
HEADER_REF_ITEM_ID = "ItemID"
HEADER_REF_PRICE_ID = "PriceID"
HEADER_REF_ATTRIBUTE_VALUE_SET_ID = "AttributeValueSetID"
HEADER_REF_VARIATION_STRING = "VariationString"
HEADER_REF_ITEM_FREE1 = "ItemFree1"

HEADER_ROW_ITEM_ID = "RowItemID"
HEADER_ROW_ATTRIBUTE_SELECTION = "RowAttributeSelection"
HEADER_ROW_PRICE_ID = "RowPriceID"
HEADER_ROW_WEIGHT = "RowWeight"
HEADER_ROW_EXT_ID = "RowItemExternalID"
HEADER_ROW_ITEM_TEXT = "RowItemText"

MISSING_VALUE = "-2"
MISSING_WEIGHT = "150"


def get_column_index(row, col_name):
    if not col_name:
        return -1

    if not row or len(row) == 0:
        return -1

    row_lower = [x.lower() for x in row]
    col_name_lower = col_name.lower()

    if col_name_lower in row_lower:
        return row_lower.index(col_name_lower)

    return -1


def setup_logging(log_path):
    # Set up logging
    l = logging.getLogger()

    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    stdout_hdlr = logging.StreamHandler(sys.stdout)
    stdout_hdlr.setLevel(logging.DEBUG)
    stdout_hdlr.setFormatter(formatter)

    datetime_file_name = time.strftime("%Y%m%d-%H%M%S")
    log_file_name = datetime_file_name + '.log'
    log_file = os.path.join(log_path, log_file_name)

    file_hdlr = logging.FileHandler(log_file)
    file_hdlr.setLevel(logging.DEBUG)
    file_hdlr.setFormatter(formatter)

    l.addHandler(stdout_hdlr)
    l.addHandler(file_hdlr)

    return l


def read_ref(ref_file):

    ref_dict = dict()

    header_read = False
    sku_index = -1
    item_index = -1
    price_index = -1
    attr_index = -1
    free1_index = -1
    # var_index = -1

    with codecs.open(ref_file, "rb", encoding='utf-8') as f:
        reader = csv.reader(f, delimiter=';')

        for row in reader:
            if header_read:
                sku = row[sku_index]

                if sku and sku.strip():
                    if sku in ref_dict:
                        logger.warning("Duplicate sku {}".format(sku))
                    else:
                        # RowAttributeSelection + RowItemID + RowPriceID + RowWeight
                        ref_dict[sku] = {HEADER_REF_ITEM_ID: row[item_index],
                                         HEADER_REF_PRICE_ID: row[price_index],
                                         HEADER_REF_ATTRIBUTE_VALUE_SET_ID: row[attr_index],
                                         # HEADER_REF_VARIATION_STRING: row[var_index],
                                         HEADER_REF_ITEM_FREE1: row[free1_index]}
            else:
                # sku;ItemID;PriceID;AttributeValueSetID;VariationString;ItemFree1
                sku_index = get_column_index(row, HEADER_REF_SKU)
                item_index = get_column_index(row, HEADER_REF_ITEM_ID)
                price_index = get_column_index(row, HEADER_REF_PRICE_ID)
                attr_index = get_column_index(row, HEADER_REF_ATTRIBUTE_VALUE_SET_ID)
                # var_index = get_column_index(row, HEADER_REF_VARIATION_STRING)
                free1_index = get_column_index(row, HEADER_REF_ITEM_FREE1)

                if sku_index < 0 or item_index < 0 or price_index < 0 or attr_index < 0 or free1_index < 0:
                    raise Exception("Cannot find all columns")

                header_read = True

    return ref_dict


def replace_missing(in_file, out_file, ref_dict):
    global logger

    header_read = False
    sku_index = -1
    item_index = -1
    price_index = -1
    text_index = -1
    weight_index = -1
    attr_index = -1

    with codecs.open(in_file, "r", encoding='utf-8') 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_index]

                if item_id == MISSING_VALUE:
                    sku = row[sku_index]
                    if sku in ref_dict:
                        ref_values = ref_dict[sku]

                        row[item_index] = ref_values[HEADER_REF_ITEM_ID]
                        row[attr_index] = ref_values[HEADER_REF_ATTRIBUTE_VALUE_SET_ID]
                        row[price_index] = ref_values[HEADER_REF_PRICE_ID]

                        t = row[text_index]
                        if "]" in t:
                            p = t.rindex("]") + 1
                            row[text_index] = t[:p] + " " + ref_values[HEADER_REF_ITEM_FREE1]

                        row[weight_index] = MISSING_WEIGHT
                    else:
                        logger.warning("Could not find {} in reference.".format(sku))
            else:
                # RowAttributeSelection;RowItemExternalID;RowItemID;RowItemPrice;RowItemText;RowOrderID;RowPositionID;
                # RowPositionReferrerID;RowPriceID;RowQuantity;RowSize;RowVAT;RowWarehouseID;RowWeight

                sku_index = get_column_index(row, HEADER_ROW_EXT_ID)
                item_index = get_column_index(row, HEADER_ROW_ITEM_ID)
                attr_index = get_column_index(row, HEADER_ROW_ATTRIBUTE_SELECTION)
                price_index = get_column_index(row, HEADER_ROW_PRICE_ID)
                weight_index = get_column_index(row, HEADER_ROW_WEIGHT)
                text_index = get_column_index(row, HEADER_ROW_ITEM_TEXT)

                if sku_index < 0 or item_index < 0 or attr_index < 0 or price_index < 0 or weight_index < 0 \
                        or text_index < 0:
                    raise Exception("Not all column found in input file.")

                header_read = True
            writer.writerow(row)


def process_files(data_root):
    global logger

    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")
    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

    logger = setup_logging(path_log)

    ref_dict = None

    try:
        ref_dict = read_ref(os.path.join(path_ref, "704_Matching_Order_Zuordnen_ref.csv"))
    except Exception as e:
        print("Exception in REF")
        logger.error(e)

    if ref_dict:
        for f in files:
            in_file = os.path.join(path_in, f)
            out_file_name = os.path.splitext(f)[0] + '.csv'
            out_file = os.path.join(path_out, out_file_name)
            proc_file = os.path.join(path_proc, f)
            err_file = os.path.join(path_err, f)

            logger.debug("Processing {0}...".format(in_file))

            if os.path.isfile(in_file):
                try:
                    replace_missing(in_file, out_file, ref_dict)
                    shutil.move(in_file, proc_file)
                except Exception as e:
                    logger.error(e)
                    shutil.move(in_file, err_file)
                    os.remove(out_file)


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

    data_root = os.path.join(data_root, "Matching_Order_Zuordnen")
    process_files(data_root)

if __name__ == "__main__":
    main()

