import logging
from contextlib import suppress

import click
from click import ClickException

from yappa.cli_helpers import (
    NaturalOrderGroup, create_function_version, create_gateway,
    ensure_function, get_missing_details, update_gateway,
)
from yappa.config_generation import (
    create_default_config,
)
from yappa.handlers.manage import FORBIDDEN_COMMANDS
from yappa.s3 import delete_bucket
from yappa.settings import (
    DEFAULT_ACCESS_KEY_FILE, DEFAULT_CONFIG_FILENAME,
    YANDEX_OAUTH_URL,
)
from yappa.utils import load_yaml, save_yaml
from yappa.yc import YC
from yappa.yc.access import save_key
from yappa.yc.function_call import call_manage_function

logger = logging.getLogger(__name__)


@click.group(cls=NaturalOrderGroup)
def cli():
    pass


@cli.command(short_help="setup YC access")
@click.argument("config-file", type=click.Path(exists=False),
                default=DEFAULT_CONFIG_FILENAME, )
@click.option("-t", '--token', default="",
              help="yandex OAuth token", envvar="YC_OAUTH"
              )
def setup(config_file, token):
    """
    setup of cloud access:

    \b
      - asks for OAuth token
      - asks for cloud to work with
      - asks for folder to work with
      - creates service account (editor) and saves access key to .yc
      - saves folder_id and s3_account_name to yappa.yaml


    *you can skip this step if YC_OAUTH and YC_FOLDER in env vars
    (see README for authentication details)
    """
    click.echo("Welcome to " + click.style("Yappa", fg="yellow") + "!")
    if not token:
        click.echo(f"Please obtain OAuth token at "
                   + click.style(YANDEX_OAUTH_URL, fg="yellow"))
        token = click.prompt("Please enter OAuth token")
    yc = YC.setup(token=token, skip_folder=True)
    clouds = {c.name: c.id for c in yc.get_clouds()}
    cloud_name = click.prompt("Please select cloud", type=click.Choice(clouds),
                              default=next(reversed(clouds)))
    folders = {f.name: f.id for f in yc.get_folders(clouds[cloud_name])}
    folder_name = click.prompt("Please select folder",
                               type=click.Choice(folders),
                               default=next(reversed(folders)))
    yc.folder_id = folders[folder_name]
    account = yc.create_service_account(f"yappa-creator-account-{folder_name}")
    save_key(yc.create_service_account_key(account.id))
    click.echo("Saved service account credentials at " + click.style(
        DEFAULT_ACCESS_KEY_FILE, bold=True))

    config = (load_yaml(config_file, safe=True)
              or create_default_config(config_file))
    config["folder_id"] = folders[folder_name]
    config["service_account_names"]["creator"] = account.name
    save_yaml(config, config_file)
    click.echo("Saved Yappa config file at "
               + click.style(config_file, bold=True))


@cli.command(short_help='generate config files, create function & api-gateway')
@click.argument("config-file", type=click.Path(exists=False),
                default=DEFAULT_CONFIG_FILENAME, )
def deploy(config_file):
    """\b
    - generates yappa.yaml (skipped if file exists)
    - creates function
    - creates function version (with uploaded to s3 package)
    - generates yappa-gw.yaml (skipped if file exists)
    - creates api-gateway
    """
    config = (load_yaml(config_file, safe=True)
              or create_default_config(config_file))
    config, is_updated = get_missing_details(config)
    if is_updated:
        save_yaml(config, config_file)
        click.echo("saved Yappa config file at "
                   + click.style(config_file, bold=True))
    yc = YC.setup(config=config)
    function = ensure_function(yc, config["project_slug"],
                               config["description"], True)
    if config['django_settings_module']:
        ensure_function(yc, config["manage_function_name"],
                        config["description"], False)
    create_function_version(yc, config)
    if config["gw_config"]:
        is_new = create_gateway(yc, config, function.id)
        if not is_new:
            update_gateway(yc, config)


@cli.command()
@click.argument("config-file", type=click.Path(exists=True),
                default=DEFAULT_CONFIG_FILENAME, )
def undeploy(config_file):
    """
    deletes function, api-gateway and bucket
    """
    config = load_yaml(config_file)
    yc = YC.setup(config=config)
    with suppress(ValueError):
        click.echo(f"Deleting function {config['project_slug']}...")
        yc.delete_function(config["project_slug"])

    with suppress(ValueError):
        click.echo(f"Deleting api-gateway {config['project_slug']}...")
        yc.delete_gateway(config['project_slug'])
    with suppress(ValueError):
        click.echo(f"Destroying bucket {config['bucket']}...")
        delete_bucket(config["bucket"], **yc.get_s3_key(
            config["service_account_names"]["creator"]))
    click.echo("That's it! Only service account is left.\n"
               + click.style("Bye!", fg="yellow"))


@cli.command(context_settings=dict(ignore_unknown_options=True,
                                   help_option_names=[], ))
@click.option("--config-file", type=click.Path(exists=True),
              default=DEFAULT_CONFIG_FILENAME, )
@click.argument("command", type=str)
@click.argument('args', nargs=-1, type=click.UNPROCESSED)
def manage(config_file, command, args):
    if command in FORBIDDEN_COMMANDS:
        raise ClickException("Sorry. You cannot run this command with "
                             "Serverless setup")
    config = load_yaml(config_file, safe=False)
    yc = YC.setup(config=config)
    function = yc.get_function(config["manage_function_name"])
    response = call_manage_function(yc, function.id, command, args)
    click.echo(response)


if __name__ == '__main__':
    cli()
