#!/usr/bin/env python
# -*- coding: utf-8 -*-

import logging
import argparse
import json
import re
import requests
import difflib
import copy

import search.tools.devops.libs.utils as u
import search.tools.devops.libs.nanny_services as ns

from saas.tools.devops.lib23.ask_for_user_action import ask_yes_or_no

import tempfile
import os

CMS_URL_BASE = 'http://cmsearch.n.yandex.ru/res/gencfg/'
CMS_URL_BASE_REGEXP = '^((http|https)://cmsearch(.n.|.)yandex.ru/res/gencfg/)(.*)(/w-generated/.*)'

MMETA_CONFIG_NAME_REGEXP = '^apache.ywsearch.cfg.*'


def fetch_generated_config(tag, context):

    cms_resource_url = CMS_URL_BASE + tag + context
    r = requests.get(cms_resource_url)

    if not r.ok:
        raise Exception("Can't get {}".format(cms_resource_url))

    return r.content


def fetch_service_configs(service):

    runtime_attributes = ns.get_service_runtime_attrs(service).json()
    files = runtime_attributes['content']['resources']

    configs = []
    for distribution_type in files.keys():
        for file_description in files[distribution_type]:

            if len(re.findall(MMETA_CONFIG_NAME_REGEXP, file_description['local_path'])) > 0:
                configs.append(file_description)
                configs[-1]['distribution_type'] = distribution_type

    return configs


def build_new_configs(configs, tag):

    def extract_cms_context(url):
        matches = re.findall(CMS_URL_BASE_REGEXP, url)
        assert len(matches) == 1
        (_, cms_base, __, tag, context) = matches[0]

        return context

    diff = []
    new_configs = copy.deepcopy(configs)

    for config, new_config in zip(configs, new_configs):

        if config['distribution_type'] == 'url_files':
            config_from_nanny = requests.get(config['url']).content
            cms_context = extract_cms_context(config['url'])
            config_from_cms = fetch_generated_config(tag, cms_context)
            new_config['url'] = CMS_URL_BASE + tag + cms_context  # TODO : get rid of this duplication

        else:
            raise Exception("Fetching configs with distribution_type = {} is not implemented yet".format(config['distribution_type']))

        if config_from_nanny != config_from_cms:
            diff.append({
                'local_path': config['local_path'],
                'config_from_cms': config_from_cms,
                'config_from_nanny': config_from_nanny,
                'diff': difflib.context_diff(config_from_cms, config_from_nanny)
            })

    return new_configs, diff


def update_service_configs(service, configs, tag, message):

    runtime_attrs = ns.get_service_runtime_attrs(service).json()
    runtime_attrs_prev = copy.deepcopy(runtime_attrs)

    print(json.dumps(configs, indent=2))

    for config in configs:
        if config['distribution_type'] == 'url_files':
            for i in runtime_attrs['content']['resources']['url_files']:
                print(json.dumps(i, indent=2))
                if i['local_path'] == config['local_path']:
                    print("updating config {}: was {}, now {}".format(config['local_path'], i['url'], config['url']))
                    i['url'] = config['url']
        else:
            raise Exception("Updating configs with distribution_type = {} is not implemented yet".format(config['distribution_type']))

    u.print_object_diff(new=runtime_attrs, old=runtime_attrs_prev)

    if message is None:
        comment = "Updating configs with saas/tools/devops/update_mmeta_config tool to version {}".format(tag)
    else:
        comment = "update_mmeta_config: gencfg/{} - {}".format(tag, message)

    put_json = {
        'comment': comment,
        'snapshot_id': runtime_attrs['_id'],
        'content': runtime_attrs['content']
    }

    put_data = json.dumps(put_json)
    response = ns.put_service_attrs(service, ns.RUNTIME_ATTRS, put_data)
    if response.ok:
        new_snapshot_id = response.json()['_id']
        logging.info("Commited, status code %s, new snapshot %s", response.status_code, new_snapshot_id)
    else:
        logging.error("Error, status code %s, response: %s", response.status_code, response.text)


def parse_cmd_args():

    description = '''
Update mmeta configs

You need to have defined OAuth tokens for nanny and sandbox in your ENV, just like this:
    export OAUTH_NANNY='{Get your token here : https://nanny.yandex-team.ru/ui/#/oauth/}'
    export OAUTH_SANDBOX='{Get your token here : https://sandbox.yandex-team.ru/oauth/}'

Good example how to use
# ./update_mmeta_config --gitdiff -s saas_refresh_3day_hamsterrr_mmeta_isolated -t stable-123-r301

'''

    parser = argparse.ArgumentParser(description=description)

    parser.add_argument(
        '-t', '--new-tag',
        # nargs='+',
        type=str,
        help='Target tag to update configs'
    )

    parser.add_argument(
        '-s', '--service',
        type=str,
        default='saas_refresh_3day_devrecluster_base_multilang_i024',
        help='Service to recluster'
    )

    parser.add_argument(
        '-d', '--debug',
        default=False,
        action='store_true',
        help='Dump actual debug info'
    )

    parser.add_argument(
        '-m',
        type=str,
        dest='message',
        help='Commit message'
    )

    parser.add_argument(
        '-g', '--gitdiff',
        default=False,
        action='store_true',
        help='Use git to show diff (instead of vimdiff)'
    )

    return parser.parse_args()


def main():

    args = parse_cmd_args()
    if args.debug:
        u.logger_setup(verbose_level=2)
        logging.info("Config : {}".format(str(args)))
    else:
        u.logger_setup(verbose_level=1)

    service = args.service
    tag = args.new_tag

    configs = fetch_service_configs(service)
    print(json.dumps(configs, indent=2))

    new_configs, diff = build_new_configs(configs, tag)
    for elementary_diff in diff:

        if ask_yes_or_no("do you want to see diff for {} (left is nanny, right is {})?".format(elementary_diff['local_path'], tag)):

            config_from_nanny = tempfile.NamedTemporaryFile(prefix='config_from_nanny')
            config_from_nanny.write(elementary_diff['config_from_nanny'])
            config_from_nanny.flush()

            config_from_cms = tempfile.NamedTemporaryFile(prefix='config_from_cms')
            config_from_cms.write(elementary_diff['config_from_cms'])
            config_from_cms.flush()

            if args.gitdiff:
                os.system("git diff --word-diff {} {}".format(config_from_nanny.name, config_from_cms.name))
            else:
                os.system("vimdiff {} {}".format(config_from_nanny.name, config_from_cms.name))

    if ask_yes_or_no("Do you want to update configs for service {}? (y/n)".format(service)):
        update_service_configs(service, new_configs, tag, args.message)
    else:
        return


if __name__ == "__main__":

    main()
