#!/usr/bin/python3

"""
Script acting as a single configuration provider for a set of datasets
distributed in various points of an institution,

It can either serve the config files itself, or generate a version of what
would be server on-disk, to be served as static content by a regular web
server.

For design discussions, see:

 - https://github.com/ARPA-SIMC/arkimet/issues/114
 - https://github.com/ARPA-SIMC/arkimet/issues/205

See also doc/http-api.rst
"""

from typing import List
import argparse
import arkimet as arki
from arkimet.dataset.http.aliases import AliasMerger
import logging
import sys
import os
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse


log = logging.getLogger("arki-web-proxy")


class Fail(Exception):
    pass


def parse_sections(configs: List[str]):
    sections = arki.cfg.Sections()
    for cfg in configs:
        if cfg.startswith("http://") or cfg.startswith("https://"):
            for name, section in arki.dataset.http.load_cfg_sections(cfg).items():
                sections[name] = section
        elif os.path.isfile(cfg):
            for name, section in arki.dataset.read_configs(cfg).items():
                sections[name] = section
        elif os.path.isdir(cfg) and os.path.exists(os.path.join(cfg, "config")):
            section = arki.dataset.read_config(cfg)
            sections[section["name"]] = section

    return sections


def do_dump(args):
    sections = parse_sections(args.config)

    alias_merger = AliasMerger(log)
    alias_merger.fetch_aliases(sections)

    os.makedirs(args.dest, exist_ok=True)
    alias_merger.aliases.write(os.path.join(args.dest, "aliases"))

    with open(os.path.join(args.dest, "config"), "wt") as fd:
        sections.write(fd)

    for name, section in sections.items():
        destdir = os.path.join(args.dest, "dataset", name)
        os.makedirs(destdir, exist_ok=True)
        with open(os.path.join(destdir, "config"), "wt") as fd:
            s = arki.cfg.Sections()
            s[name] = section
            s.write(fd)


def do_serve(args):
    sections = parse_sections(args.config)

    alias_merger = AliasMerger(log)
    alias_merger.fetch_aliases(sections)

    class ConfigHandler(BaseHTTPRequestHandler):
        def do_GET(self):
            try:
                self.handle_request()
            except Exception as e:
                self.send_response(500)
                log.exception(e)

        def handle_request(self):
            path = urlparse(self.path).path
            if path == "/":
                self.send_response(200)
                self.send_header('Content-type', 'text/plain')
                self.end_headers()
                sections.write(self.wfile)
            elif path in ("/aliases", "/aliases/"):
                self.send_response(200)
                self.send_header('Content-type', 'text/plain')
                self.end_headers()
                alias_merger.aliases.write(self.wfile)
            elif path.startswith("/dataset/"):
                name = os.path.split(path)[1]
                if name in sections:
                    section = sections[name]
                    s = arki.cfg.Sections()
                    s[name] = section
                    self.send_response(200)
                    self.send_header('Content-type', 'text/plain')
                    self.end_headers()
                    s.write(self.wfile)
                else:
                    self.send_response(404)
                    self.end_headers()
            else:
                self.send_response(404)
                self.end_headers()

    server = HTTPServer((args.host, args.port), ConfigHandler)
    server.serve_forever()


def main():
    parser = argparse.ArgumentParser(description="Arkimet proxy")
    parser.add_argument("--verbose", "-v", action="store_true", help="verbose output")
    parser.add_argument("--debug", action="store_true", help="debug output")

    subparsers = parser.add_subparsers(title='subcommands',
                                       description='valid subcommands')

    dump_parser = subparsers.add_parser('dump', help='Write config to file')
    dump_parser.add_argument("-d", "--dest", action="store", metavar="dir",
                             default=".", help="destination dir (default: .)")
    dump_parser.add_argument("config",
                             nargs="*",
                             help="Dataset or config")
    dump_parser.set_defaults(execute=do_dump)

    serve_parser = subparsers.add_parser('serve', help='Web server')
    serve_parser.add_argument("-H", "--host", default="localhost")
    serve_parser.add_argument("-p", "--port", type=int, default="8080")
    serve_parser.add_argument("config",
                              nargs="*",
                              help="Dataset or config")
    serve_parser.set_defaults(execute=do_serve)

    args = parser.parse_args()

    log_format = "%(levelname)s %(message)s"
    level = logging.WARN
    if args.debug:
        level = logging.DEBUG
    elif args.verbose:
        level = logging.INFO
    logging.basicConfig(level=level, stream=sys.stderr, format=log_format)

    args.execute(args)


if __name__ == "__main__":
    try:
        main()
    except Fail as e:
        print(e, file=sys.stderr)
        sys.exit(1)
    except Exception:
        log.exception("uncaught exception")
