"""
loans.py

Final working version of the mutation automation

Mutates items from special excel file from inventory type
CI - Centralized Inventory to type
ZDI - Zimmer Distributor Inventory

Written by: Ian Doarn
Maintained by: Ian Doarn
"""
from zbsmsa.site import Site
from zbsmsa.inventory.stock import Stock, ProductChooser
from zbsmsa.utils.exceptions import InvalidRange, ItemAddError
import xlrd
import ctypes
import sys
import time
import logging
import os
from datetime import datetime

# TODO: Comment this file

__author__ = "Ian Doarn"
__maintainer__ = "Ian Doarn"
__current_date__ = '{:%m-%d-%Y}'.format(datetime.now())

PATH = os.path.dirname(os.path.realpath(__file__))
LOG_FILE_NAME = 'mutation_loans_{}.log'.format(__current_date__)
LOG_FILE_PATH = os.path.join(PATH, LOG_FILE_NAME)
MB_OK = 0x0
MB_HELP = 0x4000
ICON_EXLAIM = 0x30
ICON_INFO = 0x40
ICON_STOP = 0x10

# if os.path.isfile(os.path.join(PATH, LOG_FILE_NAME)):
#     os.remove(os.path.join(PATH, 'LOG_FILE_NAME))
# elif os.path.isfile(LOG_FILE_PATH):
#     os.remove(LOG_FILE_PATH)
# else:
if not os.path.isfile(LOG_FILE_PATH):
    with open(LOG_FILE_PATH, 'w')as l_file:
        l_file.close()

logger = logging.getLogger()
handler = logging.FileHandler(LOG_FILE_PATH)
formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)


def message_box(title, text, style, log=True):
    if log:
        logger.info("[{}]: {}".format(title, text))
    ctypes.windll.user32.MessageBoxW(0, text, title, style)


def load_workbook(file):
    workbook = xlrd.open_workbook(file)
    sheets = []
    for sheet in workbook.sheets():
        try:
            headers = sheet.row_values(0)
            rows = []
            for y in range(1, sheet.nrows):
                row_dict = dict(zip(headers, sheet.row_values(y)))
                if row_dict['serial_number'] == '' and row_dict['lot_number'] == '':
                    logger.warning("Missing lot and serial at sheet:{} row:{} item:{} lot/serial:{}".format(
                        sheet.name, str(y + 1), row_dict['product_number'], 'NULL'
                    ))
                else:
                    row_dict['row'] = str(y + 1)
                    rows.append(row_dict)
            sheets.append({'sheet_name': sheet.name,
                           'data': rows,
                           'headers': headers,
                           'total_rows': sheet.nrows})
            del rows
            del headers
        except Exception:
            sheets.append({'sheet_name': sheet.name,
                           'data': None,
                           'headers': None,
                           'total_rows': None})
    return sheets


def mutate_loans(site, stock, product_chooser, data, note="CI-ZDI Mutation, Loaners Late Debit Policy"):
    time.sleep(3)
    site.ribbon("InventoryTab")
    stock.stock_tab()
    for row in data:
        current_site = site.get_site_name()

        logger.info('logged into [{}]'.format(site.get_site_name()))

        current_item_info = "Item: {} Lot: {} Row: {}".format(
            row['product_number'],
            row['lot_number'],
            row['row'])

        if row['distributor'] != current_site:
            site.change_site(row['distributor'])
            logger.info("site changed to [{}]".format(site.get_site_name()))
            site.ribbon("InventoryTab")
            stock.stock_tab()

        stock.stock_tab_product_chooser()

        product_chooser.search(row['product_number'])
        time.sleep(3)
        try:
            product_chooser.add(row['product_number'])
        except ItemAddError as iae:
            message_box('Error',
                        'Unable to add [{}] to the product chooser. '
                        'Please add this manually and press ok to continue!'.format(current_item_info),
                        MB_OK | ICON_INFO)
        product_chooser.finish()

        stock.stock_tab_search()
        time.sleep(3)
        stock.iterate_search_table()

        try:
            for table_row in stock.current_table_data:
                if row['lot_number'] != '' and row['serial_number'] == '':
                    tr_text = table_row['text']
                    if tr_text.__contains__(row['lot_number']) and tr_text.__contains__('CASE-'+row['case_number']):
                        stock.select_row(table_row['row'])
                        try:
                            if stock.mutate_stock(note, click_ok_on_error=False):
                                logger.info("SUCCESSFUL MUTATION: [{}]".format(current_item_info))
                                break
                            else:
                                message_box("Mutation",
                                            "Item was not mutated!"
                                            "\nItem:{} Lot:{} Row:{}".format(row['product_number'],
                                                                             row['lot_number'],
                                                                             row['row']),
                                            MB_OK | ICON_INFO)
                        except Exception as m_error:
                            message_box('Error', "{}. {}\nPlease close any open menus and errors then press ok"
                                        " to continue.".format(m_error, current_item_info), MB_OK | ICON_INFO,
                                        log=False)
                            logger.error("MutationError:{} {}".format(m_error, current_item_info))
                            break
                        break
                elif str(int(row['serial_number'])) != '':
                    tr_text = table_row['text']
                    if tr_text.__contains__(row['case_number']) and tr_text.__contains__(
                                    "Serial " + row['serial_number']):
                        stock.select_row(table_row['row'])
                        try:
                            if stock.mutate_stock(note, click_ok_on_error=False):
                                logger.info("SUCCESSFUL MUTATION: [{}]".format(current_item_info))
                                break
                            else:
                                message_box("Mutation", "Item was not mutated! {}".format(current_item_info),
                                            MB_OK | ICON_INFO)
                        except Exception as m_error:
                            message_box('Error', "{}. {}\nPlease close any open menus and errors then press ok"
                                        " to continue.".format(m_error, current_item_info), MB_OK | ICON_INFO,
                                        log=False)
                            logger.error("MutationError:{} {}".format(m_error, current_item_info))
                            break
                        break
        except ValueError as val_error:
            message_box('Error', "No Records found. [{}] {}".format(val_error, current_item_info), MB_OK | ICON_INFO)
        except InvalidRange as ivr_error:
            message_box('Error', ivr_error.message + " {}".format(current_item_info), MB_OK | ICON_INFO)
        except Exception as other_error:
            message_box('Error', str(other_error) + " {}".format(current_item_info), MB_OK | ICON_INFO)
        else:
            continue


def mutate_bins(site, stock, product_chooser, data, note="CI-ZDI Mutation, Loaners Late Debit Policy"):
    time.sleep(3)
    site.ribbon("InventoryTab")
    stock.stock_tab()
    for row in data:
        current_item_info = "Item: {} Lot: {} Row: {}".format(
            row['product_number'],
            row['lot_number'],
            row['row'])
        if row['bin'] == 'CI MISSING ZONE-0-0':
            message_box('Error', 'Can not mutate item in bin [{}]: {}'.format(row['bin'], current_item_info),
                        MB_OK | ICON_EXLAIM, log=False)
            logger.warning('Can not mutate item in bin [{}]: {}'.format(row['bin'], current_item_info))

        else:
            current_site = site.get_site_name()

            logger.info('logged into [{}]'.format(site.get_site_name()))

            if row['name'] != current_site:
                site.change_site(row['name'])
                logger.info("site changed to [{}]".format(site.get_site_name()))
                site.ribbon("InventoryTab")
                stock.stock_tab()

            stock.stock_tab_product_chooser()

            product_chooser.search(row['product_number'])
            time.sleep(3)
            try:
                product_chooser.add(row['product_number'])
            except ItemAddError as iae:
                message_box('Error',
                            'Unable to add [{}] to the product chooser. '
                            'Please add this manually and press ok to continue!'.format(current_item_info),
                            MB_OK | ICON_INFO)
            product_chooser.finish()

            stock.stock_tab_search()
            time.sleep(3)
            stock.iterate_search_table()

            try:
                for table_row in stock.current_table_data:
                    if row['lot_number'] != '' and row['serial_number'] == '':
                        tr_text = table_row['text']
                        bin_num = ''
                        if row['bin'] == 'location_bin':
                            if tr_text.__contains__('Location Bin'):
                                bin_num = 'Location Bin'
                            if tr_text.__contains__('Consigned'):
                                bin_num = 'Consigned'
                        else:
                            bin_num = row['bin']
                        if tr_text.__contains__(row['lot_number']) and tr_text.__contains__(bin_num):
                            stock.select_row(table_row['row'])
                            try:
                                if stock.mutate_stock(note, click_ok_on_error=False):
                                    logger.info("SUCCESSFUL MUTATION: [{}]".format(current_item_info))
                                    break
                                else:
                                    message_box("Mutation",
                                                "Item was not mutated!"
                                                "\nItem:{} Lot:{} Row:{}".format(row['product_number'],
                                                                                 row['lot_number'],
                                                                                 row['row']),
                                                MB_OK | ICON_INFO)
                            except Exception as m_error:
                                message_box('Error', "{}. {}\nPlease close any open menus and errors then press ok"
                                            " to continue.".format(m_error, current_item_info), MB_OK | ICON_INFO,
                                            log=False)
                                logger.error("MutationError:{} {}".format(m_error, current_item_info))
                                break
                            break
                    elif row['serial_number'] != '':
                        tr_text = table_row['text']
                        bin_num = ''
                        if row['bin'] == 'location_bin':
                            if tr_text.__contains__('Location Bin'):
                                bin_num = 'Location Bin'
                            if tr_text.__contains__('Consigned'):
                                bin_num = 'Consigned'
                        else:
                            bin_num = row['bin']
                        if tr_text.__contains__(bin_num) and tr_text.__contains__("Serial " + row['serial_number']):
                            stock.select_row(table_row['row'])
                            try:
                                if stock.mutate_stock(note, click_ok_on_error=False):
                                    logger.info("SUCCESSFUL MUTATION: [{}]".format(current_item_info))
                                    break
                                else:
                                    message_box("Mutation", "Item was not mutated! {}".format(current_item_info),
                                                MB_OK | ICON_INFO)
                            except Exception as m_error:
                                message_box('Error', "{}. {}\nPlease close any open menus and errors then press ok"
                                            " to continue.".format(m_error, current_item_info), MB_OK | ICON_INFO,
                                            log=False)
                                logger.error("MutationError:{} {}".format(m_error, current_item_info))
                                break
                            break
            except ValueError as val_error:
                message_box('Error', "No Records found. [{}] {}".format(val_error, current_item_info),
                            MB_OK | ICON_INFO)
            except InvalidRange as ivr_error:
                message_box('Error', ivr_error.message + " {}".format(current_item_info),
                            MB_OK | ICON_INFO)
            except Exception as other_error:
                message_box('Error', str(other_error) + " {}".format(current_item_info),
                            MB_OK | ICON_INFO)
            else:
                continue


def main(username, password, file, driver):
    site = Site(username, password, driver, launch=False)
    mutation_data = load_workbook(file)

    site.launch(maximize=False)

    # Log launch information
    logger.debug("USER[{}]".format(username))
    logger.debug("DRIVER[{}]".format(driver))
    logger.debug("FILE[{}]".format(file))
    logger.debug("URI[{}]".format(site.driver_uri))
    logger.debug("SESSIONID[{}]".format(site.driver_session_id))

    stock = Stock(site)
    pc = ProductChooser(stock)

    message_box("Mutation", "Please press ok when the site has fully loaded",
                MB_OK | ICON_INFO, log=False)

    site.login()

    for sheet in mutation_data:
        if sheet['sheet_name'] == 'Loans Transferred':
            mutate_loans(site, stock, pc, sheet['data'])
        if sheet['sheet_name'] == 'Bin Transferred':
            mutate_bins(site, stock, pc, sheet['data'])

    site.close()


if __name__ == '__main__':
    usage = "loans.py [username] [password] [driver location] [file location]"
    if len(sys.argv[1:]) not in [4, 5]:
        print(usage)
    else:
        _user = sys.argv[1]
        _pass = sys.argv[2]
        _drive_loc = sys.argv[3]
        _file_loc = sys.argv[4]
        try:
            logger.info("Begin program execution at main()")
            main(_user, _pass, _file_loc, _drive_loc)
        except KeyboardInterrupt as ki_error:
            message_box("Fatal Error", "[FATAL]::Fatal error caused program to fail.\nERROR:{}".format(ki_error),
                        MB_OK | ICON_STOP, log=False)
            logger.critical("[FATAL]:: Fatal error caused program to fail. ERROR:{}".format(ki_error))
        except Exception as fatal_error:
            message_box("Fatal Error", "[FATAL]::Fatal error caused program to fail.\nERROR:{}".format(fatal_error),
                        MB_OK | ICON_STOP, log=False)
            logger.critical("[FATAL]:: Fatal error caused program to fail. ERROR:{}".format(fatal_error))
        else:
            pass
