import os
import sys

from docopt import docopt
from rockset.credentials import Credentials
from .command import Command


def _format_secret(value):
    if value is None:
        return None
    i = 1
    if len(value) >= 20:
        i = 4
    return '%s**********%s' % (value[:i], value[-i:])


def _prompt_api_key(api_key=None):
    return [
        {
            'key': 'api_key',
            'message': 'Enter Rockset API key',
            'prompt': '  API Key',
            'default': {
                'display': _format_secret(api_key),
                'value': api_key,
            }
        }
    ]


def _prompt_api_server(api_server=None):
    return [
        {
            'key': 'api_server',
            'message': 'Enter Rockset API server URL',
            'prompt': '  API Server',
            'default': {
                'display': api_server,
                'value': api_server,
            }
        }
    ]


def _interactive_prompt(config):
    out = {}
    for item in config:
        key = item['key']
        message = item['message']
        prompt = item['prompt']
        default = item['default']
        if 'display' in default:
            prompt += ' [%s]' % default['display']
        sys.stdout.write(message + '\n')
        sys.stdout.write(prompt + ': ')
        sys.stdout.flush()
        value = input()
        value = value.strip()
        if value == '':
            value = default.get('value', '')
        out[key] = value
    return out


class Configure(Command):
    def usage(self):
        return """
usage: rock configure [--help]
       rock configure [options]
       rock configure add <profile> [options]
       rock configure update <profile> [options]
       rock configure ls
       rock configure rm <profile>
       rock configure select <profile>

Manage Rockset credential profiles. Each profile is associated
with an API key and an API endpoint.

commands:
    add, update       create a new credentials profile or update an existing one
                      Default, when no profiles exist.
    ls                list all profiles.
                      Default, when 1 or more profiles exist.
    rm                remove profile
    select            select profile to use for subsequent rock commands

arguments:
    <profile>         name of the profile you wish to create or update

options:
  -h, --help                    show this help message and exit
  -k, --api_key=API_KEY         specify API key to use for subsequent commands
  -s, --api_server=API_SERVER   specify API server URL assigned to your account
        """

    def go(self):
        creds = Credentials()

        # determine default command when none is specified
        if (
            not self.add and not self.update and not self.ls and not self.rm and
            not self.select
        ):

            # this is the `rock configure [options]` case
            # each case is explicitly called out for code readability
            # if api_key or api_server is specified in command-line,
            # then do `rock configure add default`
            if self.api_key or self.api_server:
                self.add = True
                self.profile = 'default'
            # if this is just `rock configure` and no profiles are found
            # then do `rock configure add default`
            elif len(creds.get_all_profiles()) == 0:
                self.add = True
                self.profile = 'default'
            # else just list all profiles
            else:
                self.ls = True

        # update is same as add
        if self.add or self.update:
            new_profile = self.profile
            ip = creds.get(new_profile)
            ip['api_key'] = ip.get('api_key', None)
            ip['api_server'] = ip.get(
                'api_server', 'https://api.rs2.usw2.rockset.com'
            )
            # dont prompt if command-line options are specified
            if self.api_key or self.api_server:
                ip['api_key'] = self.api_key or ip['api_key']
                ip['api_server'] = self.api_server or ip['api_server']
            else:
                ip = _interactive_prompt(
                    _prompt_api_key(ip['api_key']) +
                    _prompt_api_server(ip['api_server'])
                )
            ip['profile'] = new_profile
            profile_details = creds.set(
                profile=ip['profile'],
                api_key=ip['api_key'],
                api_server=ip['api_server']
            )
            if len(creds.get_all_profiles()) == 1:
                creds.active_profile(ip['profile'])
            creds.save()
        elif self.select:
            select_profile = self.profile
            active_profile = creds.active_profile(select_profile)
            if active_profile != select_profile:
                self.error('Could not switch to profile "%s"!' % select_profile)
            else:
                creds.save()
        elif self.rm:
            rm_profile = self.profile
            deleted_profile = creds.delete(rm_profile)
            if deleted_profile is None:
                self.error('No profile with name "%s" exists!' % rm_profile)
            else:
                creds.save()

        # print all profiles in alphabetical order
        all_profiles = creds.get_all_profiles()
        all_profile_names = list(all_profiles.keys())
        all_profile_names.sort()

        # accumulate formatted profiles
        profiles = []
        for pn in all_profile_names:
            profiles.append(
                self._format_profile(
                    pn, all_profiles[pn], creds.active_profile()
                )
            )

        self.print_list(
            0,
            profiles,
            field_order=['profile', 'api_server', 'api_key'],
            header=True
        )
        if self.format == 'text':
            self.lprint(0, 'Credentials stored in %s' % creds.creds_file)

        return 0

    def _format_profile(self, p, pd, ap):
        # prefix profile name with '*' if current
        if p == ap:
            prefix = '* '
        else:
            prefix = '  '
        pd['profile'] = prefix + p

        # don't show full api_key
        pd['api_key'] = _format_secret(pd.get('api_key', None))
        return pd
