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

import csv
import codecs
import logging
import logging.config
import os
import shutil
import time

logger = logging.getLogger(__name__)
logger.setLevel(logging.NOTSET)

HEADER_REF_EAN_TEXT = "Universal Product Code"
HEADER_REF_PROD_CODE_TEXT = "Product Code"
HEADER_REF_DEF_SIZE_TEXT = "Default Size Description"

HEADER_ROW_AVAIL_DATE_TEXT = "Verfügbarkeitsdatum"
HEADER_ROW_AVAILABLE_SIZES_TEXT = "Verfügbare Größen"
HEADER_ROW_COLOR_TEXT = "Artikelfarbe"
HEADER_ROW_WHOLESALE_PRICE_TEXT = "Großhandelspreis"
HEADER_ROW_ITEM_NAME_TEXT = "Artikelname"
HEADER_ROW_RETAIL_PRICE_TEXT = "Einzelhandelspreis"

AVAILABLE_NOW = "Jetzt verfügbar"
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
    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 create_key(code, size):
    return code + "_" + size

def read_ref(ref_path):
    ref_dict = dict()

    files = os.listdir(ref_path)

    for file in files:
        # Reset vars
        header_read = False
        ean_index = -1
        prod_code_index = -1
        def_size_index = -1

        ref_file = os.path.join(ref_path, file)
        logger.debug("Reading ref file {}...".format(file))
        with codecs.open(ref_file, "rb", encoding='utf-8') as f:
            reader = csv.reader(f, delimiter=';')

            for row in reader:
                if header_read:
                    prod_code = row[prod_code_index].strip()
                    def_size = row[def_size_index].strip()

                    if prod_code and def_size:
                        key = create_key(prod_code, def_size)
                        if key not in ref_dict:
                            ean = row[ean_index].strip()
                            if len(ean) == 14:
                                ean = ean[1:]

                            ref_dict[key] = ean
                        # else:
                        #     print("Duplicate found {} in {}".format(key, file))
                else:
                    ean_index = get_column_index(row, HEADER_REF_EAN_TEXT)
                    prod_code_index = get_column_index(row, HEADER_REF_PROD_CODE_TEXT)
                    def_size_index = get_column_index(row, HEADER_REF_DEF_SIZE_TEXT)

                    if ean_index < 0:
                        raise Exception("Cannot find column '{}' in ref".format(HEADER_REF_EAN_TEXT))

                    if prod_code_index < 0:
                        raise Exception("Cannot find column '{}' in ref".format(HEADER_REF_PROD_CODE_TEXT))

                    if def_size_index < 0:
                        raise Exception("Cannot find column '{}' in ref".format(HEADER_REF_DEF_SIZE_TEXT))

                    header_read = True

    logger.debug("Read a total of {} ref keys.".format(len(ref_dict)))

    return ref_dict


def extract_inventory(in_file, out_file, miss_file, ref_dict):
    header_read = False
    avail_date_index = -1
    color_index = -1
    wholesale_price_index = -1
    size_index = -1
    retail_price_index = -1
    name_index = -1
    miss_written_header = False

    with codecs.open(in_file, "r", encoding='utf-8') as f, \
            codecs.open(out_file, "w", encoding='utf-8') as of, \
            codecs.open(miss_file, "w", encoding='utf-8') as mf:

        reader = csv.reader(f, delimiter=';')
        writer = csv.writer(of, delimiter=';', quoting=csv.QUOTE_NONNUMERIC)
        miss_writer = csv.writer(mf, delimiter=';', quoting=csv.QUOTE_NONNUMERIC)

        #  Artikelnummer;Size;Bestand;Price;EAN
        for row in reader:
            if header_read:
                if not row[0]:
                    # Reset the size and read the new values for this section
                    sizes = []
                    # This is the size row
                    curr_index = size_index
                    curr_size = row[curr_index].strip()
                    while curr_size:
                        sizes.append(curr_size)
                        curr_index += 1
                        curr_size = row[curr_index].strip()
                else:
                    if row[avail_date_index] == AVAILABLE_NOW:
                        color_code = row[color_index]
                        wholesale_price_text = row[wholesale_price_index]
                        item_name = row[name_index]

                        if " " in wholesale_price_text:
                            wholesale_price_text = wholesale_price_text.split(" ")[0]

                        wholesale_price_text = wholesale_price_text.replace(",", ".")
                        try:
                            price = float(wholesale_price_text)
                        except ValueError as ve:
                            price = 0
                            logger.error(ve)

                        retail_price_text = row[retail_price_index]

                        if " " in retail_price_text:
                            retail_price_text = retail_price_text.split(" ")[0]

                            retail_price_text = retail_price_text.replace(",", ".")
                        try:
                            retail_price = float(retail_price_text)
                        except ValueError as ve:
                            retail_price = 0
                            logger.error(ve)

                        for i in range(len(sizes)):
                            size = sizes[i]
                            key = create_key(color_code, size)
                            if key in ref_dict:
                                ean = ref_dict[key]
                                stock_text = row[size_index + i].replace("+", "")
                                try:
                                    stock_amt = int(stock_text)
                                    if stock_amt > 0:
                                        writer.writerow([color_code, size, stock_amt, price, ean, retail_price, 
                                                         item_name])
                                except ValueError as ve:
                                    logger.debug("Failed to convert {} to number".format(stock_text))
                                    logger.error(ve)
                            else:
                                # logger.warning("Could not find {} in reference.".format(key))
                                if not miss_written_header:
                                    miss_writer.writerow(["unmatched_ref_key"])
                                    miss_written_header = True
                                miss_writer.writerow([key])
            else:
                avail_date_index = get_column_index(row, HEADER_ROW_AVAIL_DATE_TEXT)
                color_index = get_column_index(row, HEADER_ROW_COLOR_TEXT)
                wholesale_price_index = get_column_index(row, HEADER_ROW_WHOLESALE_PRICE_TEXT)
                size_index = get_column_index(row, HEADER_ROW_AVAILABLE_SIZES_TEXT)
                retail_price_index = get_column_index(row, HEADER_ROW_RETAIL_PRICE_TEXT)
                name_index = get_column_index(row, HEADER_ROW_ITEM_NAME_TEXT)

                if avail_date_index < 0 or color_index < 0 or wholesale_price_index < 0 or size_index < 0 or \
                    name_index < 0 or retail_price_index < 0:
                    raise Exception("Not all column found in input file.")

                header_read = True
                writer.writerow(["Artikelnummer", "Size", "Bestand", "Price", "EAN", "Retail", "Name"])


def process_files(data_root):
    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)

    setup_logging(path_log)

    logger.info("Found {0} files...".format(num_files))

    if num_files == 0:
        return

    ref_dict = None

    try:
        ref_dict = read_ref(path_ref)
    except Exception as e:
        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)
            miss_file_name = os.path.splitext(f)[0] + "_nomatch" + '.csv'
            miss_file = os.path.join(path_out, miss_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:
                    extract_inventory(in_file, out_file, miss_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)

    logging.shutdown()

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    

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

if __name__ == "__main__":
    main()