#!python
# This file is placed in the Public Domain.


import inspect
import json
import os
import sys
import time


sys.path.insert(0, os.getcwd())


from tob.clients import Client
from tob.command import Commands, command, scanner, table
from tob.handler import Event
from tob.methods import parse
from tob.package import Mods, getmod, inits, modules, sums
from tob.persist import Workdir, moddir, pidname, skel
from tob.runtime import daemon, forever, pidfile, privileges
from tob.runtime import level, wrap, wrapped
from tob.utility import md5sum, spl


from tobot import modules as MODS


CHECKSUM = "ec14aadb68aeb36827e819cf400293c0"
CHECKSUM = ""


class Config:

    debug = False
    default = "irc,rss"
    init  = ""
    level = "warn"
    name = "tobot"
    opts = ""
    verbose = False
    version = 4


class CLI(Client):

    def __init__(self):
        Client.__init__(self)
        self.register("command", command)

    def raw(self, txt):
        print(txt.encode('utf-8', 'replace').decode("utf-8"))


class Console(CLI):

    def callback(self, event):
        if not event.txt:
            return
        super().callback(event)
        event.wait()

    def poll(self):
        evt = Event()
        evt.txt = input("> ")
        evt.type = "command"
        return evt


"scripts"


def background():
    daemon("-v" in sys.argv)
    privileges()
    boot(MODS, CHECKSUM, False)
    Commands.add(cmd, ver)
    pidfile(pidname(Config.name))
    inits(spl(Config.default), Config)
    forever()


def console():
    import readline # noqa: F401
    boot(MODS, CHECKSUM)
    Commands.add(cmd, ver)
    csl = Console()
    for _mod, thr in inits(spl(Config.sets.init), Config):
        if "w" in Config.opts:
            thr.join(30.0)
    csl.start()
    forever()


def control():
    if len(sys.argv) == 1:
        return
    boot(MODS, CHECKSUM)
    Commands.add(cmd, md5, tbl, srv, ver)
    csl = CLI()
    evt = Event()
    evt.orig = repr(csl)
    evt.txt = " ".join(sys.argv[1:])
    evt.type = "command"
    command(evt)
    evt.wait()


def service():
    privileges()
    boot(MODS, CHECKSUM, False)
    banner()
    Commands.add(cmd, ver)
    pidfile(pidname(Config.name))
    inits(spl(Config.default), Config)
    forever()


"utility"


def banner():
    tme = time.ctime(time.time()).replace("  ", " ")
    print("%s %s since %s (%s)" % (Config.name.upper(), Config.version, tme, Config.level.upper()))
    sys.stdout.flush()


def boot(mods, checksum, doparse=True):
    Mods.add("modules", os.path.dirname(inspect.getfile(mods)))
    Mods.add("mods", moddir())
    if doparse:
        parse(Config, " ".join(sys.argv[1:]))
        Config.level = Config.sets.level or Config.level
    level(Config.level)
    if "v" in Config.opts:
        banner()
    Workdir.wdr = Workdir.wdr or os.path.expanduser(f"~/.{Config.name}")
    if "a" in Config.opts:
        Config.sets.init = ",".join(modules())
    skel()
    table()
    sums(checksum)


def check(txt):
    args = sys.argv[1:]
    for arg in args:
        if not arg.startswith("-"):
            continue
        for char in txt:
            if char in arg:
                return True
    return False


"commands"


def cmd(event):
    event.reply(",".join(sorted(Commands.names or Commands.cmds)))


def md5(event):
    tbl = getmod("tbl")
    if tbl:
        event.reply(md5sum(tbl.__file__))
    else:
        event.reply("table is not there.")


def srv(event):
    import getpass
    name = getpass.getuser()
    event.reply(TXT % (Config.name.upper(), name, name, name, Config.name))


def tbl(event):
    Commands.names = {}
    scanner()
    event.reply("# This file is placed in the Public Domain.")
    event.reply("")
    event.reply("")
    event.reply('"lookup tables"')
    event.reply("")
    event.reply("")
    event.reply(f"NAMES = {json.dumps(Commands.names, indent=4, sort_keys=True)}")
    event.reply("")
    event.reply("")
    event.reply("MD5 = {")
    for module in scanner():
        event.reply(f'    "{module.__name__.split(".")[-1]}": "{md5sum(module.__file__)}",')
    event.reply("}")


def ver(event):
    event.reply(f"{Config.name.upper()} {Config.version}")


"data"


TXT = """[Unit]
Description=%s
After=network-online.target

[Service]
Type=simple
User=%s
Group=%s
ExecStart=/home/%s/.local/bin/%s -s

[Install]
WantedBy=multi-user.target"""


"runtime"


def main():
    if check("c"):
        wrap(console)
    elif check("d"):
        background()
    elif check("s"):
        wrapped(service)
    else:
        wrapped(control)


"trampoline"


if __name__ == "__main__":
    main()
