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


import logging
import os
import sys
import threading
import time


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


from rssbot.clients import Client, Config
from rssbot.command import Commands, command, parse, scan
from rssbot.handler import Event
from rssbot.loggers import level
from rssbot.objects import update
from rssbot.package import Mods, getmod, modules
from rssbot.persist import Workdir, moddir, pidname
from rssbot.threads import launch, threadhook
from rssbot.utility import daemon, forever, pidfile, privileges, wrap
from rssbot.utility import check, spl, where, wrapped


NAME = "rssbot"


Config.name = NAME
Config.version = 655


Workdir.init(NAME)
Mods.init(f"{NAME}.modules")


class CLI(Client):

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

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


class Console(CLI):

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

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


"in the begining"


def banner(name, version):
    tme = time.ctime(time.time()).replace("  ", " ")
    logger = logging.getLogger()
    print("%s %s since %s (%s)" % (
                                   name.upper(),
                                   version,
                                   tme,
                                   logging.getLevelName(logger.getEffectiveLevel())
                                  ))
    sys.stdout.flush()


def scanner(names, init=False):
    mods = []
    for name in names:
        mod = getmod(name)
        if mod:
            scan(mod)
        if init and "init" in dir(mod):
            thr = launch(mod.init, Config())
            mods.append((mod, thr))
    return mods


"scripts"


def background():
    daemon(check("v"))
    privileges()
    level("info")
    scanner(modules(), True)
    Commands.add(cmd, ver)
    pidfile(pidname(Config.name))
    forever()


def console():
    import readline # noqa: F401
    parse(Config, " ".join(sys.argv[1:]))
    level(Config.sets.get("level", "info"))
    if "v" in Config.opts:
        banner(Config.name, Config.version)
    mods = []
    if "a" in Config.opts:
        mods = modules()
    else:
        mods = spl(Config.sets.get("init", ""))
    Commands.add(cmd, ver)
    csl = Console()
    for _mod, thr in scanner(mods, True):
        thr.join(30.0)
    csl.start()
    forever()


def control():
    if len(sys.argv) == 1:
        return
    scanner(modules(), False)
    Commands.add(cmd, srv, ver)
    csl = CLI()
    csl.silent = False
    evt = Event()
    evt.orig = repr(csl)
    evt.text = " ".join(sys.argv[1:])
    evt.type = "command"
    command(evt)
    evt.wait()


def service():
    privileges()
    level("info")
    banner(Config.name, Config.version)
    scanner(modules(), True)
    Commands.add(cmd, ver)
    pidfile(pidname(Config.name))
    forever()


"commands"


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


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


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"""


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


"runtime"


threading.excepthook = threadhook


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


if __name__ == "__main__":
    main()
