import logging
import os
import sys
from datetime import datetime


DEBUG = -1
INFO = 0
EMPH = 1
WARNING = 2
ERROR = 3
FATAL = 4

log_level = INFO
line_seg = "".join(["*"] * 65)


class LoggerFatalError(SystemExit):
    pass


def _format(level, messages):
    timestr = datetime.strftime(datetime.now(), "%m.%d/%H:%M")
    f = logging.currentframe()
    rv = "(unknown file)", 0, "(unknown function)"
    while hasattr(f, "f_code"):
        co = f.f_code
        filename = os.path.normcase(co.co_filename)
        if filename == logging._srcfile:
            f = f.f_back
            continue
        rv = (co.co_filename, f.f_lineno, co.co_name)
        break
    file_name, file_lnr, func_name = rv
    file_name = os.path.basename(file_name).replace(".py", "")
    func_info = f'{file_name}{"."+func_name if level == "D" else ""}:L{file_lnr}'

    m = " ".join(map(str, messages))
    msg = f"{level} {timestr} {func_info}] {m}"
    return msg


_log_file = None
_log_buffer = []
_RED = "\033[0;31m"
_GREEN = "\033[1;32m"
_LIGHT_RED = "\033[1;31m"
_ORANGE = "\033[0;33m"
_YELLOW = "\033[1;33m"
_NC = "\033[0m"  # No Color


def set_file(fname):
    global _log_file
    global _log_buffer
    if _log_file is not None:
        warning("Change log file to %s" % fname)
        _log_file.close()
    _log_file = open(fname, "w")
    if len(_log_buffer):
        for s in _log_buffer:
            _log_file.write(s)
        _log_file.flush()


def debug(*messages, file=None):
    if log_level > DEBUG:
        return
    msg = _format("D", messages)

    if file is None:
        sys.stdout.write(_YELLOW + msg + _NC + "\n")
        sys.stdout.flush()
    else:
        with open(file, "a+") as f:
            print(msg, file=f)


def info(*messages, file=None):
    if log_level > INFO:
        return
    msg = _format("I", messages)
    if file is None:
        sys.stdout.write(msg + "\n")
        sys.stdout.flush()
    else:
        with open(file, "a+") as f:
            print(msg, file=f)


def emph(*messages, file=None):
    if log_level > EMPH:
        return
    msg = _format("EM", messages)
    if file is None:
        sys.stdout.write(_GREEN + msg + _NC + "\n")
        sys.stdout.flush()
    else:
        with open(file, "a+") as f:
            print(msg, file=f)


def warning(*messages, file=None):
    if log_level > WARNING:
        return
    msg = _format("W", messages)
    if file is None:
        sys.stderr.write(_ORANGE + msg + _NC + "\n")
        sys.stderr.flush()
    else:
        with open(file, "a+") as f:
            print(msg, file=f)


def error(*messages, file=None):
    if log_level > ERROR:
        return
    msg = _format("E", messages)
    if file is None:
        sys.stderr.write(_RED + msg + _NC + "\n")
        sys.stderr.flush()
    else:
        with open(file, "a+") as f:
            print(msg, file=f)


def fatal(*messages, file=None):
    if log_level > FATAL:
        return
    msg = _format("F", messages)
    if file is None:
        sys.stderr.write(_LIGHT_RED + msg + _NC + "\n")
        sys.stderr.flush()
    else:
        with open(file, "a+") as f:
            print(msg, file=f)

    raise LoggerFatalError(-1)
