'''
SPECIAL THANKS to Heimo Stieg (https://github.com/coreGreenberet) for implementing the "aio_" examples as well as this
script, which generates the contents of the "aio" directory for running asynchronously.
'''


import csv
from datetime import datetime
import os
import logging
import re
import io

_logger = logging.Logger("")


def create_logger(log_file_prefix, print_console) -> logging.Logger:
    logger = logging.getLogger(__name__)
    log_file = f"{log_file_prefix}_log__{datetime.now():%Y-%m-%d_%H-%M-%S}.log"
    logging.basicConfig(
        filename=log_file,
        level=logging.DEBUG,
        format="%(asctime)s %(name)12s: %(levelname)8s > %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )

    if print_console:
        console = logging.StreamHandler()
        console.setLevel(logging.DEBUG)
        formatter = logging.Formatter("%(name)12s: %(levelname)8s > %(message)s")
        console.setFormatter(formatter)
        logging.getLogger("").addHandler(console)

    return logger


def get_aio_path(path, filename) -> str:
    """helper function to return the correct for a converted file based on the original file path"""

    if not os.path.isfile(os.path.join(path, filename)):
        raise ValueError(f"{os.path.join(path,filename)} is not a file")

    if "api" in path:
        path, _ = os.path.split(path)
        return os.path.join(path, "aio", "api", filename)
    else:
        return os.path.join(path, "aio", filename)


def read_file(filepath):
    """reads the file into memory and returns it contents"""

    _logger.info(f"Reading {filepath}")
    # read file into memory
    contents = None
    with open(filepath, "r") as f:
        contents = f.read()
    return contents


def compile_regex():
    """this function will compile all needed regex patterns for the conversion
    returns a tuple of dictionaries for the meraki/__init__.py file and all files under the api directory
    """
    patternInitFile = {}
    patternAPIFile = {}

    # all patterns for meraki/__init__.py
    patternInitFile[re.compile("from \.legacy import \*\n")] = ""
    patternInitFile[re.compile("from \.config import")] = "from ..config import"
    patternInitFile[
        re.compile("class DashboardAPI\(object\):")
    ] = "class AsyncDashboardAPI:"
    patternInitFile[re.compile("(from \.api\..*import )(.*)")] = r"\1Async\2"
    patternInitFile[
        re.compile("self\._session = RestSession\(")
    ] = "self._session = AsyncRestSession("
    patternInitFile[re.compile("(self\..*) = (.*\(self\._session\))")] = r"\1 = Async\2"
    patternInitFile[
        re.compile("\n$")
    ] = """

    async def __aenter__(self):
        return self

    async def __aexit__(self, exc_type, exc, tb):
        await self._session.close()
"""

    # patterns for meraki/api/*.py files
    patternAPIFile[
        re.compile("super\([a-zA-Z0-9_]+, self\)\.__init__\(\)")
    ] = "super().__init__()"
    patternAPIFile[re.compile("class ([a-zA-Z0-9]+)\(object\):")] = r"class Async\1:"
    patternAPIFile[re.compile("def ([^_].*)")] = r"async def \1"
    patternAPIFile[
        re.compile("return self\._session\.")
    ] = "return await self._session."

    return patternInitFile, patternAPIFile


def convert_file(path, filename, patternDict):
    content = read_file(os.path.join(path, filename))

    _logger.info("Starting Conversion")

    for p, v in patternDict.items():
        content, count = p.subn(v, content)
        _logger.debug(f"Applied pattern {p.pattern} {count} times")

    _logger.info("Finished Conversion")

    aioFile = get_aio_path(path, filename)
    with open(aioFile, "w") as f:
        f.write(content)
    _logger.info(f"File {aioFile} saved")


def main():
    # make sure that the aio/api directory does exist
    if not os.path.exists("meraki/aio"):
        os.makedirs("meraki/aio")
    if not os.path.exists("meraki/aio/api"):
        os.makedirs("meraki/aio/api")

    patternInitFile, patternAPIFile = compile_regex()
    convert_file("meraki", "__init__.py", patternInitFile)
    apifolder = "meraki/api"

    for file in os.listdir("meraki/api"):
        if os.path.isfile(os.path.join(apifolder, file)) and file[-3:] == ".py":
            convert_file(apifolder, file, patternAPIFile)


if __name__ == "__main__":
    start_time = datetime.now()
    _logger = create_logger(log_file_prefix=__file__[:-3], print_console=True)
    main()
    end_time = datetime.now()
    _logger.info(f"\nScript complete, total runtime {end_time - start_time}")
