# This file exposes the fromJsonToExcel function, which is used to
# generate an excel file based on json files. It takes in a base directory,
# and assumes that every direct subdirectory is a language (see directory tree below).
# It iterates through every json file in every language, generating a spreedsheet for that file
# Example of input directory
#
#  I18n
#  |
#  |-+ de
#  |   |- audits.json
#  |   |- dashboard.json
#  |   |- login.json
#  |
#  |-+ en
#  |   |- audits.json
#  |   |- dashboard.json
#  |   |- login.json
#  |
#  |-+ es
#  |   |- audits.json
#  |   |- dashboard.json
#  |   |- login.json
#  |   |- extra.json <--- The language directories don't necessary have to have the same json files.
#  |                      If a file is missing in other directories, the excel fille wil treat is as missing keys.
#  |
#  |-+ fr
#  |   |- audits.json
#  |   |- dashboard.json
#  |   |- login.json
#
# Generated excel file from exmaple input directory (filled with mock data) with audits spredsheet open
#  +---------------------------------------------+
#  | audits.json | de    | en    | es    | fr    |
#  |---------------------------------------------|
#  |             |       |       |       |       |
#  |---------------------------------------------|
#  | example/key | Hallo | Hello | Hola  | Bonjour
#  |----------------------------------------------
#  | example/key2| Beispiel Example Ejemplo Exemple
#  |_____________________________________________|
#  | audits | dashboard | login | extra |  <--- List of spredsheets
#  --------------------------------------
# Note that all empty string values ( "" <- this) will be replaced by their identifier so that they are
# genarated properly when converting back to json. This identifier is emptyStrIdentifier in the code.
import xlsxwriter
import json
import logging
import os
from collections import OrderedDict

# TODO: Add flag for one input directory
# TODO: Add flag for multiple language directories
# TODO: Add flag to generate worksheets for one directory
# TODO: Add flag for "." preprocessing
# TODO: Add flag for text that represents empty str ('') (default $JHEMPTY)
# TODO: Add verbose flag

# Utility function for processing nested json keys generated by reading json files
# It saves the keys in a directory called keys (or toWrite in the function)
# The keys paramater is a dictionary of keys from the read json file (from json.loads)
# Language is the current language
# AllInputDirs is a dictionary of langauges
# EmptyStrIdentifier is the identifier string for the json value ''
def proessData(keys, keyPath, toWrite, language, allInputDirs, emptyStrIdentifier, separator):
    for k, v in keys.items():
        if type(v) == dict:
            proessData(v, separator.join([keyPath, k]), toWrite, language, allInputDirs, emptyStrIdentifier, separator)
        else:
            toWrite.setdefault(separator.join([keyPath, k]), {i: {} for i in allInputDirs})
            # Checking if a string is empty
            if (v != ""):
                toWrite[separator.join([keyPath, k])][language] = v
            else:
                # String is empty, replace it with identifier
                toWrite[separator.join([keyPath, k])][language] = emptyStrIdentifier

# Function for processing a json file
# It has the json file name, and it check if it exists in every language directory,
# and if it does, it processses it's keys and writes them in the excel spredsheet at the end
# It passes the emptyStrIdentifier to the processData function
def processFile(filename, emptyStrIdentifier, separator, workbook, inputDirs, currentDir, language_row_format):
    worksheet = workbook.add_worksheet(os.path.basename(filename).split(".")[0][:32])
    keys = OrderedDict()
    worksheet.write(0, 0, filename)
    col = 0
    for languageDir in inputDirs:
        col += 1
        worksheet.write(0, col, os.path.basename(languageDir))
        try:
            with open(os.path.join(languageDir, filename), encoding="utf-8") as json_file:
                data = json.loads(json_file.read())
                proessData(data, "", keys, languageDir, inputDirs, emptyStrIdentifier, separator)
        except FileNotFoundError:
            #logging.info("{} not found in {}, but found in {}".format(filename, languageDir, currentDir))
            pass
        except (json.decoder.JSONDecodeError):
            logging.warning("Invalid json in file {}".format(filename))

    # Writing processed keys in spredsheet
    row = 2
    for k, v in keys.items():
        worksheet.write(row, 0, k[1:])
        col = 0
        for val2 in v.values():
            col += 1
            if (val2 != {}):
                worksheet.write(row, col, val2)
        row += 1

    # Adding formatting to spredsheet
    worksheet.set_column(1, len(inputDirs))
    worksheet.set_column(0, 0, 30)
    worksheet.set_row(0, cell_format=language_row_format)


# Main function
def fromJsonToExcel(globalInputDir, filepath="./output.xlsx", separator="/",
                    emptyStrIdentifier="$JHEMPTY", verbose=False, quiet=True):
    globalInputDir = os.path.join(os.getcwd(), globalInputDir)

    # Generate language directories
    inputDirs = [os.path.join(globalInputDir, i) for i in os.listdir(globalInputDir)
                 if os.path.isdir(os.path.join(globalInputDir, i))]

    # Disable logging if quiet mode is true or set logging level if it is false
    if quiet:
        logging.disable(logging.CRITICAL)
    else:
        if verbose:
            logging.basicConfig(level=logging.INFO, format="%(message)s")
        else:
            logging.basicConfig(level=logging.WARNING, format="%(message)s")

    # Check if the filepath ends with an excel file
    if os.path.split(filepath)[1].endswith('.xlsx'):
        # Create intermediate directories if they don't exist
        os.makedirs(os.path.split(filepath)[0], exist_ok=True)
        # Create excel workbook
        workbook = xlsxwriter.Workbook(filepath)
    else:
        if not quiet:
            logging.critical("The filepath does not end with with an excel file (it needs to end with a file that has the .xlsx extension)")
            quit()
        else:
            raise NameError("The filepath does not end with with an excel file (it needs to end with a file that has the .xlsx extension)")

    # Create style formats
    language_row_format = workbook.add_format()
    language_row_format.set_bg_color("#c5efcd")
    language_row_format.set_bold()
    key_col_format = workbook.add_format()
    key_col_format.set_bg_color("#cbe7ff")

    # Log that processing is starting
    logging.warning("Processing from base directory \"{}\"".format(os.path.abspath(globalInputDir)))

    # Create empty dictionary of processed files
    files = {}
    for inputDir in inputDirs:
        logging.info("Checking for unprocessed files in {}".format(os.path.abspath(inputDir)))
        for filename in [i for i in os.listdir(inputDir) if os.path.isfile(os.path.join(inputDir, i)) and i.lower().endswith(".json")]:
            try:
                # Check if file has been processed before
                files[filename]
            except KeyError:
                # File has not been processed, processing it
                logging.info("Processing {}".format(filename))
                files[filename] = True
                processFile(filename, emptyStrIdentifier, separator, workbook, inputDirs, inputDir, language_row_format)

    # Done, closing file
    workbook.close()

    # Log that we are done
    logging.warning(
        "\nCreated excel file at path \"{}\"".format(os.path.abspath(filepath)))

# If the file is being run directly (without the tool)
if __name__ == "__main__":
    # Process the arguments
    import sys
    from . import processArgs
    fromJsonToExcel(*processArgs.processJsonToExcelArgs(sys.argv[1:]))
