# -*- coding: utf-8 -*-
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 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 General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import logging
import os
import shlex
import sys

import click

import kallithea
import kallithea.bin.kallithea_cli_base as cli_base
from kallithea.lib.utils2 import str2bool
from kallithea.lib.vcs.backends.git.ssh import GitSshHandler
from kallithea.lib.vcs.backends.hg.ssh import MercurialSshHandler
from kallithea.model.ssh_key import SshKeyModel, SshKeyModelException


log = logging.getLogger(__name__)


@cli_base.register_command(config_file_initialize_app=True, hidden=True)
@click.argument('user-id', type=click.INT, required=True)
@click.argument('key-id', type=click.INT, required=True)
def ssh_serve(user_id, key_id):
    """Serve SSH repository protocol access.

    The trusted command that is invoked from .ssh/authorized_keys to serve SSH
    protocol access. The access will be granted as the specified user ID, and
    logged as using the specified key ID.
    """
    ssh_enabled = kallithea.CONFIG.get('ssh_enabled', False)
    if not str2bool(ssh_enabled):
        sys.stderr.write("SSH access is disabled.\n")
        return sys.exit(1)

    ssh_locale = kallithea.CONFIG.get('ssh_locale')
    if ssh_locale:
        os.environ['LC_ALL'] = ssh_locale # trumps everything, including LANG, except LANGUAGE
        os.environ['LANGUAGE'] = ssh_locale # trumps LC_ALL for GNU gettext message handling

    ssh_original_command = os.environ.get('SSH_ORIGINAL_COMMAND', '')
    client_ip = os.environ.get('SSH_CONNECTION', '').split(' ', 1)[0] or '0.0.0.0'
    log.debug('ssh-serve was invoked for SSH command %r from %s', ssh_original_command, client_ip)

    if not ssh_original_command:
        if os.environ.get('SSH_CONNECTION'):
            sys.stderr.write("'kallithea-cli ssh-serve' can only provide protocol access over SSH. Interactive SSH login for this user is disabled.\n")
        else:
            sys.stderr.write("'kallithea-cli ssh-serve' cannot be called directly. It must be specified as command in an SSH authorized_keys file.\n")
        return sys.exit(1)

    try:
        ssh_command_parts = shlex.split(ssh_original_command)
    except ValueError as e:
        sys.stderr.write('Error parsing SSH command %r: %s\n' % (ssh_original_command, e))
        sys.exit(1)
    for VcsHandler in [MercurialSshHandler, GitSshHandler]:
        vcs_handler = VcsHandler.make(ssh_command_parts)
        if vcs_handler is not None:
            vcs_handler.serve(user_id, key_id, client_ip)
            assert False # serve is written so it never will terminate

    sys.stderr.write("This account can only be used for repository access. SSH command %r is not supported.\n" % ssh_original_command)
    sys.exit(1)


@cli_base.register_command(config_file_initialize_app=True)
def ssh_update_authorized_keys():
    """Update .ssh/authorized_keys file.

    The file is usually maintained automatically, but this command will also re-write it.
    """
    try:
        SshKeyModel().write_authorized_keys()
    except SshKeyModelException as e:
        sys.stderr.write("%s\n" % e)
        sys.exit(1)
