"""Various output and logging functions."""
import os
import subprocess as sp
import sys
from io import StringIO


LOGFILE = "commands.log"
GIT_COMMIT = ["git", "rev-parse", "--short", "HEAD"]


def log_command(project, args):
    """Log a run."""
    path = os.path.join(project, LOGFILE)
    output = sp.run(GIT_COMMIT, stdout=sp.PIPE)
    git_hash = output.stdout.strip().decode("utf-8")
    with open(path, "a") as logfile:
        call = " ".join(args)
        logfile.write("{} {}\n".format(git_hash, call))


_quiet = False
_debug = False


def set_quiet(val, print_debug=False):
    global _quiet, _debug
    _quiet = bool(val)
    _debug = bool(print_debug)


def print_results(s, *args, **kwargs):
    if _quiet:
        return

    print(s.format(*args, **kwargs), file=sys.stdout)
    sys.stdout.flush()


def notify(s, *args, **kwargs):
    "A simple logging function => stderr."
    if _quiet:
        return

    print(u"\r\033[K", end=u"", file=sys.stderr)
    print(s.format(*args, **kwargs), file=sys.stderr, end=kwargs.get("end", u"\n"))
    if kwargs.get("flush"):
        sys.stderr.flush()


def debug(s, *args, **kwargs):
    "A debug logging function => stderr."
    if _quiet or not _debug:
        return

    print(u"\r\033[K", end=u"", file=sys.stderr)
    print(s.format(*args, **kwargs), file=sys.stderr, end=kwargs.get("end", u"\n"))
    if kwargs.get("flush"):
        sys.stderr.flush()


def error(s, *args, **kwargs):
    "A simple error logging function => stderr."
    print(u"\r\033[K", end=u"", file=sys.stderr)
    print(s.format(*args, **kwargs), file=sys.stderr)
    if kwargs.get("flush"):
        sys.stderr.flush()


def test_notify():
    global _quiet

    qsave = _quiet
    saveerr, sys.stderr = sys.stderr, StringIO()
    try:
        _quiet = False
        notify(u"hello, world")
    finally:
        _quiet = qsave
        saveerr, sys.stderr = sys.stderr, saveerr

    print(type(saveerr))
    assert "hello, world\n" in saveerr.getvalue()


def test_notify_flush():
    global _quiet

    qsave = _quiet
    saveerr, sys.stderr = sys.stderr, StringIO()
    try:
        _quiet = False
        notify(u"hello, world", flush=True)
    finally:
        _quiet = qsave
        saveerr, sys.stderr = sys.stderr, saveerr

    print(type(saveerr))
    assert "hello, world" in saveerr.getvalue()


def test_notify_end():
    global _quiet

    qsave = _quiet
    saveerr, sys.stderr = sys.stderr, StringIO()
    try:
        _quiet = False
        notify(u"hello, world", end=u"FOO")
    finally:
        _quiet = qsave
        saveerr, sys.stderr = sys.stderr, saveerr

    print(type(saveerr))
    assert "hello, worldFOO" in saveerr.getvalue()


def test_notify_quiet():
    global _quiet

    qsave = _quiet
    saveerr, sys.stderr = sys.stderr, StringIO()
    try:
        _quiet = True
        notify(u"hello, world")
    finally:
        _quiet = qsave
        saveerr, sys.stderr = sys.stderr, saveerr

    print(type(saveerr))
    assert "hello, world" not in saveerr.getvalue()


def test_error():
    global _quiet

    qsave = _quiet
    saveerr, sys.stderr = sys.stderr, StringIO()
    try:
        _quiet = False
        error(u"hello, world")
    finally:
        _quiet = qsave
        saveerr, sys.stderr = sys.stderr, saveerr

    print(type(saveerr))
    assert "hello, world\n" in saveerr.getvalue()


def test_error_flush():
    global _quiet

    qsave = _quiet
    saveerr, sys.stderr = sys.stderr, StringIO()
    try:
        _quiet = False
        error(u"hello, world", flush=True)
    finally:
        _quiet = qsave
        saveerr, sys.stderr = sys.stderr, saveerr

    print(type(saveerr))
    assert "hello, world" in saveerr.getvalue()


def test_error_quiet():
    # error should still output even if _quiet is True
    global _quiet

    qsave = _quiet
    saveerr, sys.stderr = sys.stderr, StringIO()
    try:
        _quiet = True
        error(u"hello, world")
    finally:
        _quiet = qsave
        saveerr, sys.stderr = sys.stderr, saveerr

    print(type(saveerr))
    assert "hello, world" in saveerr.getvalue()
