#!/usr/bin/python3
# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Configuration helper for Matrix-Synapse server.
"""

import argparse
import json
import os
import pathlib
import sys

import yaml

from plinth import action_utils
from plinth.modules.matrixsynapse import (LISTENERS_CONF_PATH, ORIG_CONF_PATH,
                                          REGISTRATION_CONF_PATH,
                                          STATIC_CONF_PATH)

TURN_CONF_PATH = '/etc/matrix-synapse/conf.d/freedombox-turn.yaml'
OVERRIDDEN_TURN_CONF_PATH = '/etc/matrix-synapse/conf.d/turn.yaml'

STATIC_CONFIG = {
    'max_upload_size':
        '100M',
    'password_providers': [{
        'module': 'ldap_auth_provider.LdapAuthProvider',
        'config': {
            'enabled': True,
            'uri': 'ldap://localhost:389',
            'start_tls': False,
            'base': 'ou=users,dc=thisbox',
            'attributes': {
                'uid': 'uid',
                'name': 'uid',
                'mail': '',
            },
        },
    }, ],
}


def parse_arguments():
    """Return parsed command line arguments as dictionary"""
    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')

    subparsers.add_parser('post-install', help='Perform post install steps')
    help_pubreg = 'Enable/Disable/Status public user registration.'
    pubreg = subparsers.add_parser('public-registration', help=help_pubreg)
    pubreg.add_argument('command', choices=('enable', 'disable', 'status'),
                        help=help_pubreg)
    setup = subparsers.add_parser('setup', help='Set domain name for Matrix')
    setup.add_argument(
        '--domain-name',
        help='The domain name that will be used by Matrix Synapse')

    subparsers.add_parser(
        'move-old-conf',
        help='Move old configuration file to backup before reinstall')

    turn = subparsers.add_parser(
        'configure-turn',
        help='Configure a TURN server for use with Matrix Synapse')
    turn.add_argument(
        '--managed', required=False, default=False, action='store_true',
        help='Whether configuration is provided by user or auto-managed by '
        'FreedomBox')

    subparsers.required = True
    return parser.parse_args()


def subcommand_post_install(_):
    """Perform post installation configuration."""
    with open(STATIC_CONF_PATH, 'w') as static_conf_file:
        yaml.dump(STATIC_CONFIG, static_conf_file)

    # start with listener config from original homeserver.yaml
    with open(ORIG_CONF_PATH) as orig_conf_file:
        orig_config = yaml.load(orig_conf_file)

    listeners = orig_config['listeners']
    for listener in listeners:
        if listener['port'] == 8448:
            listener['bind_addresses'] = ['::', '0.0.0.0']
            listener.pop('bind_address', None)

    with open(LISTENERS_CONF_PATH, 'w') as listeners_conf_file:
        yaml.dump({'listeners': listeners}, listeners_conf_file)


def subcommand_setup(arguments):
    """Configure the domain name for matrix-synapse package."""
    domain_name = arguments.domain_name
    action_utils.dpkg_reconfigure('matrix-synapse',
                                  {'server-name': domain_name})


def subcommand_public_registration(argument):
    """Enable/Disable/Status public user registration."""
    try:
        with open(REGISTRATION_CONF_PATH) as reg_conf_file:
            config = yaml.load(reg_conf_file)
    except FileNotFoundError:
        # Check if its set in original conffile.
        with open(ORIG_CONF_PATH) as orig_conf_file:
            orig_config = yaml.load(orig_conf_file)
            config = {
                'enable_registration':
                    orig_config.get('enable_registration', False)
            }

    if argument.command == 'status':
        if config['enable_registration']:
            print('enabled')
            return
        else:
            print('disabled')
            return
    elif argument.command == 'enable':
        config['enable_registration'] = True
    elif argument.command == 'disable':
        config['enable_registration'] = False

    with open(REGISTRATION_CONF_PATH, 'w') as reg_conf_file:
        yaml.dump(config, reg_conf_file)

    action_utils.service_try_restart('matrix-synapse')


def subcommand_move_old_conf(_arguments):
    """Move old configuration to backup so it can be restored by reinstall."""
    conf_file = pathlib.Path(ORIG_CONF_PATH)
    if conf_file.exists():
        backup_file = conf_file.with_suffix(conf_file.suffix + '.fbx-bak')
        conf_file.replace(backup_file)


def _set_turn_config(conf_file):
    turn_server_config = json.loads(''.join(sys.stdin))

    if not turn_server_config['uris']:
        # No valid configuration, remove the configuration file
        try:
            os.remove(conf_file)
        except FileNotFoundError:
            pass

        return

    config = {
        'turn_uris': turn_server_config['uris'],
        'turn_shared_secret': turn_server_config['shared_secret'],
        'turn_user_lifetime': 86400000,
        'turn_allow_guests': True
    }

    with open(conf_file, 'w+') as turn_config:
        yaml.dump(config, turn_config)


def subcommand_configure_turn(arguments):
    """Set parameters for the STUN/TURN server to use with Matrix Synapse."""
    if arguments.managed:
        _set_turn_config(TURN_CONF_PATH)
    else:
        _set_turn_config(OVERRIDDEN_TURN_CONF_PATH)

    action_utils.service_try_restart('matrix-synapse')


def main():
    arguments = parse_arguments()
    sub_command = arguments.subcommand.replace('-', '_')
    sub_command_method = globals()['subcommand_' + sub_command]
    sub_command_method(arguments)


if __name__ == '__main__':
    main()
