"""
A quick and dirty public DNS script, super tightly coupled to my infrastructure.
"""

import argparse
import os
from pprint import pprint

from gandi.client import GandiAPI
import meraki
from updater import *
import yaml


parser = argparse.ArgumentParser(
    description='"Dynamic" DNS updating for self-hosted services'
)
parser.add_argument("--config", dest="config_file", required=True)
parser.add_argument("--templates", dest="template_dir", required=True)
parser.add_argument("--dry-run", dest="dry", action="store_true", default=False)


def main():
    args = parser.parse_args()

    with open(args.config_file, "r") as fp:
        config = yaml.safe_load(fp)

    dashboard = meraki.DashboardAPI(config["meraki"]["key"], output_log=False)
    org = config["meraki"]["organization"]
    device = config["meraki"]["router_serial"]

    uplinks = dashboard.appliance.getOrganizationApplianceUplinkStatuses(
        organizationId=org, serials=[device]
    )[0]["uplinks"]

    template_bindings = {
        "local": {
            # One of the two
            "public_v4s": [
                link.get("publicIp") for link in uplinks if link.get("publicIp")
            ],
        },
        # Why isn't there a merge method
        **config["bindings"],
    }

    print(f"Using config {template_bindings!r}...")

    api = GandiAPI(config["gandi"]["key"])

    for task in config["tasks"]:
        if isinstance(task, str):
            task = {"template": task + ".j2", "zones": [task]}

        computed_zone = template_and_parse_zone(
            os.path.join(args.template_dir, task["template"]), template_bindings
        )

        print(f"Running task {task!r}...")

        for zone_name in task["zones"] or []:
            try:
                live_zone = api.domain_records(zone_name)

                lr, rl = diff_zones(computed_zone, live_zone)
                if lr or rl:
                    print(f"Zone {zone_name} differs;")
                    print("Computed:")
                    pprint(computed_zone)
                    pprint("Live:")
                    pprint(live_zone)
                    if rl:
                        print("Live records not recomputed")
                        pprint(rl)
                    if lr:
                        print("New records not live")
                        pprint(lr)

                    if not args.dry:
                        print(api.replace_domain(zone_name, computed_zone))
                else:
                    print("Zone {} up to date".format(zone_name))

            except Exception as e:
                print("While processing zone {}".format(zone_name))
                raise e


if __name__ == "__main__" or 1:
    main()
