"""
/***************************************************************************
 logger

 wide area mapping
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                             -------------------
        begin                : 2022-01-01
        git sha              : $Format:%H$
        copyright            : (C) 2022 by forschung@ciss.de
        email                : forschung@ciss.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
"""
import inspect
import time
import sys
import traceback
from enum import Enum

from weissflaechenkartierung.src.tools import get_class_from_frame, get_module_name


class LogLvl(Enum):
    DEBUG = 0       # level zero
    DATA = 1        # u would like to see data for debugging purpose
    INFO = 2
    WARNING = 3
    ERROR = 4


class LogLvlTxt(Enum):
    DATA = "DATA"
    ERROR = "ERROR"
    WARNING = "WARNING"
    DEBUG = "DEBUG"
    INFO = "INFO"

    @staticmethod
    def get_text(lvl: LogLvl) -> str:
        if lvl.value == LogLvl.DEBUG.value:
            return LogLvlTxt.DEBUG.value
        if lvl.value == LogLvl.ERROR.value:
            return LogLvlTxt.ERROR.value
        if lvl.value == LogLvl.INFO.value:
            return LogLvlTxt.INFO.value
        if lvl.value == LogLvl.DATA.value:
            return LogLvlTxt.DATA.value
        if lvl.value == LogLvl.WARNING.value:
            return LogLvlTxt.WARNING.value


class Logger:
    count: int = 0
    level: LogLvl = LogLvl.DEBUG
    error_list: list = []
    whole_log: list = []

    ex_type: str = ""
    ex_value: str = ""

    @staticmethod
    def get_current_system_exception() -> str:
        ex_type, ex_value, ex_traceback = sys.exc_info()  # get current system exception

        error_msg = "<span style=\"font-size:10pt; font-family: Segoe UI; font-weight:600; color:#ff0000;\">"
        error_msg += str(ex_value)
        error_msg += "</span> "

        Logger.ex_type = str(ex_type)
        Logger.ex_value = error_msg
        trace_back = traceback.extract_tb(ex_traceback)  # stack traces as tuples
        stack_trace = list()
        for trace in trace_back:
            stack_trace.append(
                "File : %s , Line : %d, Func.Name : %s, Message : %s" % (trace[0], trace[1], trace[2], trace[3]))

        text = "\nFehler Typ: " + str(ex_type.__name__) + "\nFehler Msg: " + error_msg + "\nStack: " + str(
            stack_trace)
        return text

    @staticmethod
    def debug(txt: str):
        """
        logs onto the debug way
        """
        caller = get_module_name(get_class_from_frame(inspect.stack()[1][0]).__name__)
        if LogLvl.DEBUG.value >= Logger.level.value:
            print(Logger._create_log(txt=txt, lvl=LogLvl.DEBUG, caller=caller))

    @staticmethod
    def info(txt: str):
        """
        logs onto the debug way
        """
        caller = get_module_name(get_class_from_frame(inspect.stack()[1][0]).__name__)
        if LogLvl.INFO.value >= Logger.level.value:
            print(Logger._create_log(txt=txt, lvl=LogLvl.INFO, caller=caller))

    @staticmethod
    def data(data):
        """
        logs onto the debug way
        """
        caller = get_module_name(get_class_from_frame(inspect.stack()[1][0]).__name__)
        if LogLvl.DATA.value >= Logger.level.value:
            print(Logger._create_log(txt=str(data), lvl=LogLvl.DATA, caller=caller))

    @staticmethod
    def warning(txt: str):
        """
        logs onto the debug way
        """
        caller = get_module_name(get_class_from_frame(inspect.stack()[1][0]).__name__)
        if LogLvl.WARNING.value >= Logger.level.value:
            print(Logger._create_log(txt=txt, lvl=LogLvl.WARNING, caller=caller))

    @staticmethod
    def error(txt: str, exc_info: bool = False):
        """
        logs onto the debug way
        """
        if LogLvl.ERROR.value >= Logger.level.value:
            if exc_info:
                txt += "\n" + Logger.get_current_system_exception()

            caller = get_module_name(get_class_from_frame(inspect.stack()[1][0]).__name__)
            log_txt = Logger._create_log(txt=txt, lvl=LogLvl.ERROR, caller=caller)
            print(log_txt)
            Logger.error_list.append(log_txt)

    @staticmethod
    def get_count() -> int:
        """
        returns the total amount of logs
        """
        return Logger.count

    @staticmethod
    def _create_log(txt: str, caller: str, lvl: LogLvl) -> str:
        Logger.count += 1
        t = time.strftime("%D %H:%M:%S", time.localtime(int(time.time())))
        log = str(LogLvlTxt.get_text(lvl)) + " - " + str(t) + " - " + caller + " - " + txt
        Logger.whole_log.append(log)
        return log

    @staticmethod
    def clear_errors():
        """
        clears the global error list
        """
        Logger.error_list.clear()

    @staticmethod
    def print_errors():
        """
        prints all errors
        """
        if len(Logger.error_list) > 0:
            print("Error conclusion:")
            print(Logger.error_list)
            Logger.clear_errors()

    @staticmethod
    def to_file(path: str = "log.txt"):
        """
        prints the whole log to a file
        """
        if path:
            import os
            if os.path.exists(path):
                os.remove(path)
            with open(path, 'w+', encoding='utf-8') as f:
                f.write(Logger._create_log("Create log file", LogLvl.INFO))
                for log in Logger.whole_log:
                    f.write(log)
                f.close()
                Logger.whole_log.clear()
