#!/usr/bin/env python3
# encoding: utf-8

# hiding GCP warning since we're using user creds
import warnings

from framl.monitoring import Monitoring

warnings.filterwarnings("ignore", "Your application has authenticated using end user credentials")

import yaml
import os, sys
import click
from tabulate import tabulate
from framl.assembler import Assembler
from framl.flags import Flags
from framl.config_cli import ConfigFraml

current_path = os.getcwd()
ass = Assembler(current_path)


@click.group()
def root():
    pass


@root.command('init', help="To create and configure a new frame in the current directory")
def init():
    cli_conf = ConfigFraml()
    name = click.prompt('Model Name', type=click.STRING, err=True)
    name = name.replace(' ', '_').lower()

    gcp = click.prompt('GCP Project id', type=click.STRING, err=True)

    author = click.prompt('Author', type=click.STRING, err=True)
    git = click.prompt('Git repo URL', type=click.STRING, default="")

    desc = click.prompt('Description', type=click.STRING, default="")

    conf_dict = Assembler.create_config(model_name=name, gcp_project_id=gcp, description=desc, author=author,
                                        git_url=git)
    click.confirm(f"\nYou're about to create a frame in {current_path}/.\n"
                  f"Here is your configuration file:\n{yaml.dump(conf_dict)}\n\n"
                  f"Is this OK?", default=True, show_default=True, abort=True)

    ass.download_skeleton(
        bucket_name=cli_conf.get_skeleton_bucket(),
        name=cli_conf.get_skeleton_name(),
        tag=cli_conf.get_skeleton_tag()
    )
    ass.copy_base()
    ass.save_conf_fil(conf_dict)

    click.echo("Frame successfully created!")


@root.group()
def env():
    pass

@env.command('get', help="Get used environment")
def get_env():
    cli_conf = ConfigFraml()
    click.echo(f"Environment: {cli_conf.get_env()}")

@env.command('set', help="Set used environment")
@click.argument('env')
def set_env(env):
    if not os.path.isfile("/.dockerenv"):
        if 'FRAML_ENV' in os.environ and os.environ['FRAML_ENV'] is not None:
            raise Exception("There's FRAML_ENV variable set, please remove it in order for env set to take effect")
        cli_conf = ConfigFraml()
        cli_conf.set_env(env)
        click.echo(f"New environment: {cli_conf.get_env()}")
    else:
        click.echo("Please set env through `export FRAML_ENV=[env]`")


@root.group()
def flags():
    if not os.path.isfile(current_path + '/config.yaml'):
        raise click.UsageError('No config.yaml in the current working directory. '
                               'Please make sure you\'re at the right path')


@flags.command('list', help="List declared and hosted flags")
@click.option('--env', help="Environment to use")
def list_flags(env):
    if env is not None:
        click.echo(f"Forcing environment to: {env}")
        os.environ['FRAML_ENV'] = env
    flags_ob = Flags(current_path)
    comp = flags_ob.compare_current_with_config()
    click.echo(tabulate(comp, headers=['Declared', 'Pushed', 'Value', ''], tablefmt=""))


@flags.command('update', help="Publish declared flags (with values) to remote location")
@click.option('--env', help='Environment to use')
def publish_flags(env):
    if env is not None:
        click.echo(f"Forcing environment to: {env}")
        os.environ['FRAML_ENV'] = env
    cli_conf = ConfigFraml()
    flags_ob = Flags(current_path)
    declared = flags_ob.declared_flags
    for flag in declared:
        res = click.prompt(f'New value for {flag}', type=click.STRING, default=flags_ob.get(flag))

        # we don't know the type of the input and we need to determine it
        try:
            res = int(res)
        except ValueError:
            try:
                res = float(res)
            except ValueError:
                pass

        flags_ob.set(flag, res)

    click.echo()
    comp = flags_ob.compare_current_with_config()
    click.echo(tabulate(comp, headers=['Declared', 'Pushed', 'Value', ''], tablefmt=""))

    click.confirm(f"\nYou're sure you want to update {cli_conf.get_env()}?", default=True, show_default=True,
                  abort=True)
    flags_ob.save()
    click.echo("Flags have been updated!")


@root.group()
def monitoring():
    if not os.path.isfile(current_path + '/config.yaml'):
        raise click.UsageError('No config.yaml in the current working directory. '
                               'Please make sure you\'re at the right path')


@monitoring.command('list', help="List monitoring sources")
def list_monitoring():
    mon = Monitoring(current_path)
    info = mon.list()
    click.echo("1. All raw data are sent to:\n"
               f"\tPubsub topic {info['topic']}\n"
               f"2. Then these logs are saved in JSON files alongside other models in:\n"
               f"\tGCS bucket: {info['bucket']}\n"
               f"3. Finally fields that are monitored (see config.yaml) are copied to:\n"
               f"\tBiQuery table: {info['table']}")


@monitoring.command('prepare', help="Create or update BigQuery monitoring table and GCS logs's bucket")
def prepare_monitoring():
    mon = Monitoring(current_path)
    mon.prepare_table()
    click.echo("Ready for monitoring")


try:
    root()
except Exception as e:
    raise click.ClickException(e)
