# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2010-2014 Vifib SARL and Contributors.
# All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
##############################################################################

import re
import os
import sys

import requests

from slapos.cli.config import ClientConfigCommand
from slapos.util import mkdir_p, parse_certificate_key_pair


class ConfigureClientCommand(ClientConfigCommand):
    """
    configure slapos client with an existing account
    """

    def get_parser(self, prog_name):
        ap = super(ConfigureClientCommand, self).get_parser(prog_name)

        ap.add_argument('--master-url',
                        default='https://slap.vifib.com',
                        help='URL of SlapOS Master REST API'
                             ' (default: %(default)s)')

        ap.add_argument('--master-url-web',
                        default='https://www.slapos.org',
                        help='URL of SlapOS Master webservice to register certificates'
                             ' (default: %(default)s)')

        ap.add_argument('--token',
                        help="SlapOS 'credential security' authentication token "
                             "(use '--token ask' for interactive prompt)")

        return ap

    def take_action(self, args):
        do_configure_client(logger=self.app.log,
                            master_url_web=args.master_url_web,
                            token=args.token,
                            config_path=self.config_path(args),
                            master_url=args.master_url)


def get_certificate_key_pair(logger, master_url_web, token):
    req = requests.post('/'.join([master_url_web, 'myspace/my_account/request-a-certificate/WebSection_requestNewCertificate']),
                        data={},
                        headers={'X-Access-Token': token},
                        verify=False)

    if req.status_code == 403:
        logger.critical('Access denied to the SlapOS Master. '
                        'Please check the authentication token or require a new one.')
        sys.exit(1)

    req.raise_for_status()

    return parse_certificate_key_pair(req.text)


def fetch_configuration_template():
    # XXX: change to local version.
    req = requests.get('http://git.erp5.org/gitweb/slapos.core.git/blob_plain/HEAD:/slapos-client.cfg.example')
    req.raise_for_status()
    return req.text


def do_configure_client(logger, master_url_web, token, config_path, master_url):
    while not token:
        token = raw_input('Credential security token: ').strip()

    # Check for existence of previous configuration, certificate or key files
    # where we expect to create them. If so, ask the use to manually remove them.

    if os.path.exists(config_path):
        logger.critical('There is a file in %s. '
                        'Please remove it before creating a new configuration.', config_path)
        sys.exit(1)

    basedir = os.path.dirname(config_path)
    if not os.path.isdir(basedir):
        logger.debug('Creating directory %s', basedir)
        mkdir_p(basedir, mode=0o700)

    cert_path = os.path.join(basedir, 'client.crt')
    if os.path.exists(cert_path):
        logger.critical('There is a file in %s. '
                        'Please remove it before creating a new certificate.', cert_path)
        sys.exit(1)

    key_path = os.path.join(basedir, 'client.key')
    if os.path.exists(key_path):
        logger.critical('There is a file in %s. '
                        'Please remove it before creating a new key.', key_path)
        sys.exit(1)

    # retrieve a template for the configuration file

    cfg = fetch_configuration_template()

    cfg = re.sub('master_url = .*', 'master_url = %s' % master_url, cfg)
    cfg = re.sub('cert_file = .*', 'cert_file = %s' % cert_path, cfg)
    cfg = re.sub('key_file = .*', 'key_file = %s' % key_path, cfg)

    # retrieve and parse the certicate and key

    certificate, key = get_certificate_key_pair(logger, master_url_web, token)

    # write everything

    with os.fdopen(os.open(config_path, os.O_CREAT | os.O_TRUNC | os.O_WRONLY, 0o600), 'w') as fout:
        logger.debug('Writing configuration to %s', config_path)
        fout.write(cfg)

    with os.fdopen(os.open(cert_path, os.O_CREAT | os.O_TRUNC | os.O_WRONLY, 0o600), 'w') as fout:
        logger.debug('Writing certificate to %s', cert_path)
        fout.write(certificate)

    with os.fdopen(os.open(key_path, os.O_CREAT | os.O_TRUNC | os.O_WRONLY, 0o600), 'w') as fout:
        logger.debug('Writing key to %s', key_path)
        fout.write(key)

    logger.info('SlapOS client configuration written to %s', config_path)