import datetime
import inspect
import os
import subprocess
import sys

__outputPath = None

def isDevEnvironment():
    addon_directory_name = os.path.basename(os.path.dirname(os.path.realpath(__file__)))
    if addon_directory_name == "addon": 
        return True
    return False

def isDebugMode():
    """
    Check if the addon or blender is running in debug mode.
    This is determined by the presence of NEEDLE_DEBUG_MODE=1 environment variable or if Blender is running in debug mode.
    """
    if os.environ.get("NEEDLE_DEBUG_MODE", "0") == "1":
        return True
    # if blender is running in debug mode
    if hasattr(sys, 'gettrace') and sys.gettrace() is not None:
        return True
    return False

def getLogFilePath():
    return __outputPath

def __deleteOldLogFiles(dir):
    if not os.path.exists(dir):
        return
    files = os.listdir(dir)
    files = [os.path.join(dir, f) for f in files] # add path to each file
    files.sort(key=lambda x: os.path.getmtime(x))
    for i in range(len(files) - 20):
        file = files[i]
        if file.endswith(".log"):
            print("Remove old log: " + file)
            os.remove(file) 
        pass
    pass


def __getLogsDirectory():
    import tempfile
    tempDir = tempfile.gettempdir()
    dir = os.path.join(tempDir, "Needle", "Blender", "Logs")
    return dir

def __getOutputFilePath():
    
    # get output file path
    dir = __getLogsDirectory()
    __ensureDirExists(dir)

    # if previous log is enabled we will return the most recent log file
    # if previous_log:
    #     files = os.listdir(dir)
    #     # find the most recent log file
    #     files = [os.path.join(dir, f) for f in files] # add path to each file
    #     files.sort(key=lambda x: os.path.getmtime(x))
    #     open_next = False
    #     for i in range(len(files) - 1, -1, -1):
    #         file = files[i]
    #         if file.endswith(".log"):
    #             if open_next:
    #                 return file;
    #             open_next = True

    global __outputPath
    if __outputPath is not None:
        return __outputPath

    __deleteOldLogFiles(dir)
    timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
    path = os.path.join(dir, "needle.blender.exporter." + timestamp + ".log")
    if not os.path.exists(path):
        open(path, "w").close()
            
    return path

def __ensureDirExists(dir):
    if not os.path.exists(dir):
        os.makedirs(dir)

def __setupLogging():
    global __outputPath
    log_path = __getOutputFilePath()
    __outputPath = log_path
    print("Logging to: " + __outputPath)


__setupLogging()

def __isWindows():
    return os.name == 'nt'
def __isMac():
    return sys.platform == 'darwin'

def __open(path):
    if os.path.exists(path):
        if __isWindows():
            os.startfile(path)
        elif __isMac():
            opener ="open" if sys.platform == "darwin" else "xdg-open"
            subprocess.call([opener, path])
        else:
            opener = "open" if sys.platform == "darwin" else "xdg-open"
            subprocess.call([opener, path])


def openLogFile(open_previous=False):
    path = __getOutputFilePath()
    if os.path.exists(path):
        __open(path)

def openLogDirectory():
    directory = os.path.dirname(__outputPath)
    if os.path.exists(directory):
        __open(directory)

def getTimestamp():
    return datetime.datetime.now().strftime("%H:%M:%S")

def getLogPrefix():
    return f"{getTimestamp()} | "

## Use to debug log messages
def debug_log(*args):
    print(f"{getLogPrefix()}DEBUG: ", *args)
    callingFunctionName = inspect.stack()[1][3]
    write_log(callingFunctionName, *args)

def debug_warn(*args):
    print(f"{getLogPrefix()}WARN: ", *args)
    callingFunctionName = inspect.stack()[1][3]
    write_log(callingFunctionName, "WARN:", *args)

def debug_err(*args):
    import traceback
    trace = traceback.format_exc()
    if len(trace) > 0:
        trace = "\n" + trace
    # stacktrace = inspect.stack()
    # parsed = "\n" + parse_stacktrace(stacktrace)
    # get stacktrace from nested exception?
    # for arg in args:
    #     if isinstance(arg, Exception):
    #         # try:
    #         #     stacktrace = arg.with_traceback()
    #         #     pass
    #         # except Exception as e:
    #         #     pass
    #         pass
    print(f"{getLogPrefix()}ERR: ", *args, trace)
    write_log("ERR:", *args, trace)

def parse_stacktrace(stacktrace):
    result = ""
    for frame in stacktrace:
        file_name = os.path.basename(frame.filename)
        if frame.code_context:
            result += f"""> "{file_name}", line {frame.lineno}, in {frame.function}
        {frame.code_context[0].strip()}
"""     
        else:
            result += f"""> "{file_name}", line {frame.lineno}, in {frame.function}"""
    return result

# __logsString = ""
def write_log(callingFunctionName=None, *args):
    try:
        # global __logsString
        strArgs = ""
        for arg in args:
            if arg is None:
                strArgs += "None "
            else:
                strArgs += str(arg) + " "
        # get timestamp
        timeStamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log = timeStamp + ": " + strArgs
        if callingFunctionName is not None:
            log += " (at " + str(callingFunctionName) + ")"
        log += "\n"
        open(__outputPath, "a").write(log)
        # __logsString += log + "\n"
    except Exception as e:
        print("Error writing log: " + str(e))


def __printStartupLog():
    try:
        import bpy
        blender_version = bpy.app.version_string
        currentPathVariables = os.environ["PATH"].split(os.pathsep)
        startup_log = f"""
Blender version: {blender_version}
OS: {sys.platform}
Python: {sys.version}
PATH: {currentPathVariables}
"""
        write_log(None, startup_log)
    except Exception as e:
        print("ERR printing startup log " + str(e))
        write_log(None, "Error printing startup log: " + str(e))

__printStartupLog()

# def flush_logs():
#     global __logsString
#     if len(__logsString) > 0:
#         open(__outputPath, "a").write(__logsString)
#     __logsString = ""

