#!/usr/bin/env python
"""bind related dns methods"""

import datetime
import secrets

from waflibs import log, text, utils

default_bind_dir = "/etc/bind"
default_serial_file = f"{default_bind_dir}/serial"

INFOGREEN = "\033[32m"
INFORED = "\033[31m"
ENDCOLOR = "\033[0m"
BANNER = """\
; @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
;         THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
;
;             ALL CHANGES SHOULD BE MADE IN MYSQL ONLY
; @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
"""

logger = log.create_logger()


def restart_bind(sudo=False):
    command_arr = ["service", "bind9", "reload"]
    if sudo:
        command_arr.insert(0, "sudo")
    logger.debug("command to run: {}".format(" ".join(command_arr)))

    stdout, stderr, _ = utils.shell_command(command_arr)
    logger.debug("stdout: {}".format(stdout))
    logger.debug("stderr: {}".format(stderr))


restart = restart_bind


def sign_zone(zone, bind_dir=default_bind_dir, sudo=False):
    salt = secrets.token_hex(8)

    domain = zone
    if zone.endswith("home"):
        domain = ".".join(zone.split(".")[0:-1])

    command_arr = [
        "dnssec-signzone",
        "-S",
        "-3",
        salt,
        "-o",
        domain,
        "-N",
        "INCREMENT",
        "-f",
        f"signed/db.{zone}",
        f"db.{zone}",
    ]
    if sudo:
        command_arr.insert(0, "sudo")
    logger.debug("command to run: {}".format(" ".join(command_arr)))

    stdout, stderr, _ = utils.shell_command(command_arr, cwd=bind_dir)
    logger.debug("stdout: {}".format(stdout))
    logger.debug("stderr: {}".format(stderr))


def sign_zones(
    zones,
    bind_dir=default_bind_dir,
    sudo=False,
):
    for zone in zones:
        sign_zone(zone, bind_dir=bind_dir, sudo=sudo)


def sign_zones_and_restart(
    zones,
    bind_dir=default_bind_dir,
    sudo=False,
):
    sign_zones(zones, bind_dir=bind_dir, sudo=sudo)
    restart_bind(sudo=sudo)


sign_and_restart = sign_zones_and_restart


def generate_serial_number(
    serial_file=default_serial_file,
    serial_number=None,
):
    if serial_number is None:
        now = datetime.datetime.now()
        serial_format = "%Y%m%d"
        date_as_str = now.strftime(serial_format)
        default_serial_number = date_as_str + "00"

        try:
            s_num = open(serial_file).read().strip()
            if s_num.startswith(date_as_str):
                serial_number = int(s_num) + 1
            else:
                serial_number = default_serial_number
        except FileNotFoundError as e:
            logger.debug("serial file not found... ignoring")
            logger.debug(f"error: {e}")

            serial_number = default_serial_number

    return int(serial_number)


def write_serial_number(serial_number, serial_file):
    try:
        with open(serial_file, "w") as f:
            f.write(f"{serial_number}\n")
    except PermissionError as e:
        logger.debug(f"error writing to {serial_file}: {e}")


write_serial = write_serial_number


gen_serial_number = generate_serial_number
gen_serial_num = generate_serial_number
gen_serial = generate_serial_number
generate_serial = generate_serial_number


def generate_bind_file(
    all_records,
    domain,
    zone_file_name=None,
    template_file_name=None,
    domain_template_file_name=None,
    serial_number=generate_serial(),
    bind_dir=default_bind_dir,
    serial_file=default_serial_file,
    logger=logger,
    dry_run=False,
):
    """generate bind file from given arguments"""

    write_serial(serial_number, serial_file)

    logger.debug(f"{INFOGREEN}Generating zone records for {domain}...{ENDCOLOR}")

    logger.debug("all records: {}".format(all_records))
    count = 0
    records = ""
    for record in all_records:
        record_name = record["name"]
        record_type = record["type"]
        content = record["content"]
        proxied = record["proxied"]
        count += 1

        logger.debug(
            "record name: {}, record type: {}".format(
                text.idna(record_name), record_type
            )
        )
        logger.debug("record content: {}, proxied: {}".format(content, proxied))

        if record_type in ("MX"):
            records += "{name} IN {record_type} {priority} {content}\n".format(
                name=record_name,
                record_type=record_type,
                priority=record["priority"],
                content=content,
            )
        elif record_type in ("SRV"):
            records += "{name} IN {record_type} {priority} {content}\n".format(
                name=record_name,
                record_type=record_type,
                priority=record["data"]["priority"],
                content=content,
            )
        elif record_type in ("SPF", "TXT"):
            records += '{name} IN {record_type} "{content}"\n'.format(
                name=record_name, record_type=record_type, content=content
            )
        elif record_type in ("NS", "CNAME"):
            records += "{name} IN {record_type} {content}\n".format(
                name=record_name, record_type=record_type, content=content
            )
        elif record_type in ("A", "AAAA"):
            records += "{name} IN {record_type} {content}\n".format(
                name=record_name, record_type=record_type, content=content
            )
        else:
            logger.fatal("unsupported dns record type {}".format(record_type))

    records += """\n; {} total records found""".format(count)

    logger.debug(
        "{}Finished generating records for {}{}".format(INFOGREEN, domain, ENDCOLOR)
    )

    if zone_file_name is None:
        zone_file_name = "db.{zone}"
    zone_file = "{}/{}".format(bind_dir, zone_file_name.format(zone=domain))
    logger.debug("zone file: {}".format(zone_file))

    if template_file_name:
        template_file = open(template_file_name)
        if domain_template_file_name:
            domain_template_file = open(domain_template_file_name)
            tmpl = template_file.read() + "\n" + domain_template_file.read() + "\n"
            domain_template_file.close()
        else:
            tmpl = template_file.read() + "\n"
        contents = tmpl.format(
            banner=BANNER,
            zone=domain,
            records=records,
            serial=serial_number,
            nameserver=nameserver,
        )
        template_file.close()
    else:
        contents = "{banner}\n{records}".format(banner=BANNER, records=records)

    logger.debug("bind file: {}".format(contents))

    return write_zone_file(zone_file, contents, dry_run)


def write_zone_file(zone_file, contents, dry_run=False):
    if dry_run:
        logger.info(
            "{}would write dns zone file to {}{}".format(INFOGREEN, zone_file, ENDCOLOR)
        )
        logger.debug("contents: {}".format(contents))
    else:
        logger.debug("{}Writing to file {}...{}".format(INFOGREEN, zone_file, ENDCOLOR))
        try:
            with open(zone_file, "w") as f:
                f.write(contents)
                logger.debug(
                    f"{INFOGREEN}finished writing to file {zone_file}{ENDCOLOR}"
                )

            return zone_file
        except IOError as ioe:
            logger.debug(f"{INFORED}ERROR!{ENDCOLOR}")
            logger.fatal(ioe)
