import logging
import requests
import click

from jinja2 import Environment
from library.python import resource

from saas.library.python.bundle_networks import BundleNetworks
from saas.library.python.token_store import PersistentTokenStore
from saas.library.python.token_store.errors import TokenGetFail, TokenLoadError
from saas.library.python.saas_ctype import SaasCtype
from saas.library.python.nanny_rest import NannyServiceBase
from saas.library.python.nanny_rest.templates import proxy_service
from saas.library.python.nanny_rest.resource import SandboxFile
from saas.library.python.nanny_rest.service_mutable_proxy import NannyServiceBaseRuntimeProxy
from saas.library.python.nanny_rest.service_mutable_proxy.data_volume import VaultSecretVolume
from saas.library.python.nanny_rest.service_mutable_proxy.environment_variable import VaultSecretEnv


from saas.library.python.abc.api import AbcAPI
from saas.library.python.sandbox import SandboxApi

from saas.tools.ssm.modules.nanny_yp_api import SaaSNannyYpWorkflow
from saas.tools.ssm.modules.nanny_api import NannyServices

from saas.tools.devops.lib23.deploy_manager_api import DeployManagerApiClient
from saas.tools.devops.lib23.infra_api import Infra

# APP_URL = 'https://oauth.yandex-team.ru/client/7999105bc18c4a52b47afddb9ce12520'

REQUIRED_TOKENS = ('abc', 'infra', 'nanny', 'puncher', 'racktables', 'solomon', 'yav', 'sandbox')


class SaaS(object):
    def __init__(self):

        self.abc_id = 664
        self.abc_slug = 'saas'

        self.infra_service_id = 503


@click.command('create_saas_ctype')
@click.option('--installation', prompt='Installation name', help='Example: ydo')
@click.option('--contour', prompt='Contour name', help='Example: stable_hamster')
@click.option('--geo', multiple=True, default=['sas', 'man', 'vla'])
@click.option('-v', '--verbose', default=False, is_flag=True)
def create_saas_ctype(installation, contour, geo, verbose):
    log_level = logging.DEBUG if verbose else logging.INFO
    logging.basicConfig(level=log_level)
    try:
        bumble_tool_token = PersistentTokenStore.get_token_from_store_env_or_file('bumble')
        for service in REQUIRED_TOKENS:
            PersistentTokenStore.add_or_update_token(service, bumble_tool_token)
    except (TokenLoadError, TokenGetFail):
        logging.error('Bumble tool token not found, looking for separate tokens')
        PersistentTokenStore.ensure_tokens_for(REQUIRED_TOKENS)

    saas = SaaS()

    installation_name = installation
    contour_name = contour
    trimmed_contour_name = contour_name.replace('stable', '', 1).strip('_')
    saas_ctype = SaasCtype('{}_{}'.format(contour_name, installation_name))

    macros = BundleNetworks().create_bundle_networks(saas_ctype.name)
    print(macros)

    # TVM docs : https://wiki.yandex-team.ru/intranet/abc/api/#post/api/v4/resources/request/

    abc_api = AbcAPI()
    tvm_app = abc_api.get_or_create_searchproxy_tvm_application(installation_name, contour_name, saas.abc_id)
    tvm_app_info = abc_api.get_resources_consumers_meta_info(tvm_app['id'])

    infra = Infra()
    infra_environments = {a['name']: a['id'] for a in infra.list_environments(service=503)}
    if saas_ctype.name not in infra_environments:
        infra.create_environment(service=503, environment=saas_ctype.name)
    infra_environment_id = {a['name']: a['id'] for a in infra.list_environments(service=503)}[saas_ctype.name]

    # TODO: add sandbox scope to the app https://oauth.yandex-team.ru/client/7999105bc18c4a52b47afddb9ce12520
    sandbox_api = SandboxApi()
    searchproxy_resource = sandbox_api.get_last_released_resource('RTYSERVER_SEARCHPROXY').nanny_resource_info()
    loop_conf_resource = sandbox_api.get_last_released_resource('RTYSERVER_LOOP_CONF_YP').nanny_resource_info()
    push_client_resource = sandbox_api.get_last_released_resource('STATBOX_PUSHCLIENT').nanny_resource_info()
    tvm_secret = VaultSecretEnv(
        'TVM_SECRET', secretId=tvm_app_info['secret_uuid'], secretVer=tvm_app_info['version_uuid']
    )
    proxy_resources = {
        SandboxFile('evlogdump', 'BUILD_MIDDLESEARCH', '1216337515', 'EVLOGDUMP_EXECUTABLE'),
        SandboxFile('gdb_toolkit.tgz', 'BUILD_RTYSERVER', '1039569243', 'GDB_SEARCH_TOOLKIT'),
        SandboxFile('searchproxy', **searchproxy_resource),
        SandboxFile('loop.conf', **loop_conf_resource),
        SandboxFile('loop_data', loop_conf_resource['task_type'], loop_conf_resource['task_id'], 'RTYSERVER_LOOP_DATA'),
        SandboxFile('push-client', **push_client_resource)
    }
    for dc in geo:
        proxy_ns_name = 'saas_sp_{}_{}_{}'.format(trimmed_contour_name, installation_name, dc)
        info_attrs, runtime_attrs, auth_attrs = proxy_service(
            ctype=saas_ctype,
            loc=dc,
            sandbox_files=proxy_resources,
            infra_notifications_settings={
                'service_id': str(saas.infra_service_id),
                'service_name': 'SaaS',
                'environment_id': str(infra_environment_id),
                'environment_name': saas_ctype.name
            }
        )

        nanny_service = NannyServiceBase.create(
            proxy_ns_name,
            info_attrs,
            runtime_attrs=runtime_attrs,
            auth_attrs=auth_attrs
        )

        yp_lite_client = SaaSNannyYpWorkflow(proxy_ns_name, saas.abc_id, flexible_quota=True)
        # Here to allocate pods
        # Prepare volumes
        yp_lite_client.add_persistent_volume('/logs', 'hdd', 50 * 1024)
        yp_lite_client.add_persistent_volume('/cores', 'hdd', 50 * 1024)
        yp_lite_client.add_persistent_volume('/state', 'hdd', 1024)

        # Pods allocation
        yp_lite_client.allocate_pods(
            1 * 1000,
            10 * 1024,
            2048,
            locations=[dc.upper()],
            root_storage_type='hdd',
            cpu_limit=2 * 1000,
            instances_count=saas_ctype.proxy_instance_count,
            network_macros=macros['PROXY'].name
        )

        with nanny_service.runtime_attrs_transaction('configure secrets') as runtime_attrs:  # type: NannyServiceBaseRuntimeProxy
            runtime_attrs.instance_spec.add_volume(VaultSecretVolume('push_client_secret', 'sec-01f4gvpnx9sxkpc1g4zfa9nesj'))
            runtime_attrs.instance_spec.containers['saas_daemon'].ensure_env(tvm_secret)

        ssm_nanny = NannyServices(proxy_ns_name, config=None)  # todo: we should use nanny_rest instead
        ssm_nanny.configure_yp_instances(tags={
            'metaprj': 'saas',
            'itype': 'searchproxy',
            'ctype': saas_ctype.kind,
            'prj': saas_ctype.yasm_prj_prefix
        })

        # Here to activate nanny_service :)
        ssm_nanny.snapshot_activate(recipe='common_no_confirm')

        endpoint_set_name = proxy_ns_name.replace('_', '-')
        if endpoint_set_name not in ssm_nanny._ns.list_endpointsets().get(dc.upper(), []):
            ssm_nanny._ns.create_endpointset(
                endpoint_set_name, dc,
                protocol='tcp', port=80, description=None, pod_filter=''
            )

    dm = DeployManagerApiClient()
    dm.put_storage_file('/common/{}/cluster.meta'.format(saas_ctype.name), 'Service {}')

    jinja2_environment = Environment(trim_blocks=False, lstrip_blocks=False, keep_trailing_newline=True)
    environment_template = jinja2_environment.from_string(
        resource.find('/saas/bumble_tool/environment.j2').decode('utf-8')
    )
    environment_content = environment_template.render(
        ctype=saas_ctype.name,
        tvm_service_id=tvm_app['resource']['external_id']
    )
    dm.put_storage_file('/common/{}/environment'.format(saas_ctype.name), environment_content)

    print('Here to change /configs/searchproxy/tags.info :')
    proxy_ns_name_base = 'saas_sp_{}_{}'.format(trimmed_contour_name, installation_name)
    sp_config_section = """
      "%s":
        {
          "endpointsets":
            [
              "sas@%s-sas",
              "man@%s-man",
              "vla@%s-vla"
            ],
          "nanny_services":
            [
              "%s_sas@SAAS@",
              "%s_man@SAAS@",
              "%s_vla@SAAS@"
            ],
          "use_container_names":1
        },
    """ % (
        saas_ctype.name, proxy_ns_name_base.replace('_', '-'),
        proxy_ns_name_base.replace('_', '-'),
        proxy_ns_name_base.replace('_', '-'),
        proxy_ns_name_base,
        proxy_ns_name_base,
        proxy_ns_name_base
    )
    print(sp_config_section)

    solomon_token = PersistentTokenStore.get_token_from_store_env_or_file('solomon')
    # Here to create cluster in Solomon
    # $ curl -X POST \
    #  -H 'Content-Type: application/json' \
    #  -H 'Accept: application/json' \
    #  -H 'Authorization: OAuth <YOUR_TOKEN>' \
    #  -d @request.json \
    #  https://solomon.yandex.net/api/v2/projects/saas_ferryman/clusters
    r = requests.post(
        'https://solomon.yandex.net/api/v2/projects/saas_ferryman/clusters',
        json={
            'id': 'saas_ferryman_' + saas_ctype.name,
            'name': saas_ctype.name
        },
        headers={
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'Authorization': 'OAuth {}'.format(solomon_token),
        }
    )
    r.raise_for_status()


if __name__ == '__main__':
    create_saas_ctype()
