#!/usr/bin/env python3
import sys
import os
import logging
import argparse
import json
import unicodedata

sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'api'))
import zulip

def write_public_streams() -> None:
    public_streams = set()

    for stream_name in stream_names:
        # Zephyr class names are canonicalized by first applying NFKC
        # normalization and then lower-casing server-side
        canonical_cls = unicodedata.normalize("NFKC", stream_name).lower()
        if canonical_cls in ['security', 'login', 'network', 'ops', 'user_locate',
                             'mit', 'moof', 'wsmonitor', 'wg_ctl', 'winlogger',
                             'hm_ctl', 'hm_stat', 'zephyr_admin', 'zephyr_ctl']:
            # These zephyr classes cannot be subscribed to by us, due
            # to MIT's Zephyr access control settings
            continue

        public_streams.add(canonical_cls)

    with open("/home/zulip/public_streams.tmp", "w") as f:
        f.write(json.dumps(list(public_streams)) + "\n")
    os.rename("/home/zulip/public_streams.tmp", "/home/zulip/public_streams")

if __name__ == "__main__":
    log_file = "/home/zulip/sync_public_streams.log"
    logger = logging.getLogger(__name__)
    log_format = "%(asctime)s: %(message)s"
    logging.basicConfig(format=log_format)
    formatter = logging.Formatter(log_format)
    logger.setLevel(logging.DEBUG)
    file_handler = logging.FileHandler(log_file)
    file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)

    parser = zulip.add_default_arguments(argparse.ArgumentParser())
    options = parser.parse_args()

    zulip_client = zulip.Client(client="ZulipSyncPublicStreamsBot/0.1")
    backoff = zulip.RandomExponentialBackoff()

    while backoff.keep_going():
        try:
            res = zulip_client.register(event_types=["stream"])
            if res["result"] != "success":
                backoff.fail()
                logger.error("Error registering event queue:\n%r", res)
                continue
        except Exception:
            logger.exception("Error registering event queue:")
            continue

        backoff.succeed()
        queue_id = res["queue_id"]
        last_event_id = res["last_event_id"]
        stream_names = {stream["name"] for stream in res["streams"]}
        write_public_streams()

        while backoff.keep_going():
            try:
                res = zulip_client.get_events(queue_id=queue_id, last_event_id=last_event_id)
                if res["result"] != "success":
                    backoff.fail()
                    logger.error("Error getting events:\n%r", res)
                    if res["result"] == "error":
                        # Break out to the outer loop to re-register the event queue.
                        break
                    continue
            except Exception:
                logger.exception("Error getting events:")
                continue

            backoff.succeed()
            for event in res["events"]:
                last_event_id = max(last_event_id, event["id"])
                if event["type"] == "stream":
                    if event["op"] == "create":
                        stream_names.update(
                            stream["name"] for stream in event["streams"]
                        )
                        write_public_streams()
                    elif event["op"] == "delete":
                        stream_names.difference_update(
                            stream["name"] for stream in event["streams"]
                        )
                        write_public_streams()