#!/usr/bin/env python3
# Copyright 2015-2024 The Wazo Authors  (see the AUTHORS file)
# SPDX-License-Identifier: GPL-3.0+

import argparse
import sys

import netaddr
import netifaces
from jinja2 import Template
from xivo_dao import default_config, init_db_from_config
from xivo_dao.alchemy.dhcp import Dhcp
from xivo_dao.alchemy.mail import Mail
from xivo_dao.alchemy.netiface import Netiface
from xivo_dao.alchemy.provisioning import Provisioning
from xivo_dao.alchemy.resolvconf import Resolvconf
from xivo_dao.helpers.db_utils import session_scope

XIVO_COMMON_CONF_TEMPLATE = Template(
    """\
### AUTOMATICALLY GENERATED BY xivo-create-config. DO NOT EDIT ###

{%- for key, value in config.items() %}
XIVO_{{ key.upper() }}="{{ value if value != None}}"
{%- endfor %}

"""
)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '-o',
        '--output',
        action='store',
        default='/etc/xivo/common.conf',
        help="File where to write the output. Use '-' for stdout. Default: %(default)s",
    )
    args = parser.parse_args()
    init_db_from_config(default_config())
    config = load_config()
    with sys.stdout if args.output == '-' else open(args.output, 'w') as output:
        output.write(XIVO_COMMON_CONF_TEMPLATE.render(config=config))


def load_config():
    with session_scope() as session:
        result = {}
        result.update(load_config_dhcp(session))
        result.update(load_config_smtp(session))
        result.update(load_config_provisioning(session))
        result.update(load_config_resolvconf(session))
        result.update(load_config_netiface(session))
        return result


def load_config_dhcp(session):
    dhcp = session.query(
        Dhcp.active,
        Dhcp.pool_start,
        Dhcp.pool_end,
        Dhcp.network_interfaces,
    ).first()

    net4_ip = ''
    net4_netmask = ''
    net4_subnet = ''

    try:
        main_iface = dhcp.network_interfaces.split(',')[0]
    except IndexError:
        main_iface = None

    if main_iface:
        try:
            address = netifaces.ifaddresses(main_iface)[netifaces.AF_INET][0]
        except (KeyError, IndexError):
            address = None

        if address:
            ip_network = netaddr.IPNetwork(f'{address["addr"]}/{address["netmask"]}')
            net4_ip = str(ip_network.ip)
            net4_netmask = str(ip_network.netmask)
            net4_subnet = str(ip_network.network)

    return {
        'dhcp_active': dhcp.active,
        'dhcp_network_interfaces': dhcp.network_interfaces,
        'dhcp_pool': f'{dhcp.pool_start} {dhcp.pool_end}',
        'dhcp_net4_ip': net4_ip,
        'dhcp_net4_netmask': net4_netmask,
        'dhcp_net4_subnet': net4_subnet,
    }


def load_config_smtp(session):
    smtp = session.query(
        Mail.mydomain,
        Mail.origin,
        Mail.relayhost,
        Mail.fallback_relayhost,
        Mail.canonical,
    ).first()

    return {
        'smtp_mydomain': smtp.mydomain or None,
        'smtp_origin': smtp.origin,
        'smtp_relayhost': smtp.relayhost,
        'smtp_fallback_relayhost': smtp.fallback_relayhost,
        'smtp_canonical': smtp.canonical,
    }


def load_config_provisioning(session):
    provd = session.query(
        Provisioning.net4_ip,
        Provisioning.http_port,
        Provisioning.http_base_url,
        Provisioning.dhcp_integration,
    ).first()
    provd_net4_ip = provd.net4_ip or ''
    provd_url = provd.http_base_url or ''

    return {
        'provd_net4_ip': provd_net4_ip,
        'provd_http_port': str(provd.http_port),
        'provd_http_base_url': provd_url,
        'provd_dhcp_integration': '1',
    }


def load_config_resolvconf(session):
    resolvconf = session.query(
        Resolvconf.hostname,
        Resolvconf.domain,
        Resolvconf.nameserver1,
        Resolvconf.nameserver2,
        Resolvconf.nameserver3,
    ).first()

    return {
        'hostname': resolvconf.hostname,
        'domain': resolvconf.domain,
        'extra_dns_search': '',
        'nameservers': ' '.join(
            nameserver
            for nameserver in (
                resolvconf.nameserver1,
                resolvconf.nameserver2,
                resolvconf.nameserver3,
            )
            if nameserver
        ),
    }


def load_config_netiface(session):
    netiface = (
        session.query(
            Netiface.ifname,
            Netiface.address,
            Netiface.netmask,
        )
        .filter(Netiface.networktype == 'voip')
        .first()
    )

    return {
        'voip_ifaces': netiface.ifname,
        'net4_ip': netiface.address,
        'net4_netmask': netiface.netmask,
        'net4_subnet': str(
            netaddr.IPNetwork(f'{netiface.address}/{netiface.netmask}').network
        ),
    }


if __name__ == '__main__':
    main()
