# -*- coding: utf-8 -*-
import json
from textwrap import dedent

import vh
from startrek_client import Startrek
from datacloud.dev_utils.logging.logger import get_nirvana_logger

nirvana_logger = get_nirvana_logger(__name__)


def validate_dict_value_type(dict2validate, key, value_type):
    assert key in dict2validate, '{} not found in dict!'.format(key)
    assert isinstance(dict2validate[key], value_type), \
        '{key} should be of type `{value_type}`!'.format(
            key=key, value_type=value_type
        )


def validate_benchmark_result_format(benchmark_result):
    assert isinstance(benchmark_result, dict), '`benchamrk_result` should be `dict` instance!'
    key_value_types = [
        ('dataset_name', basestring),
        ('auc', float),
        ('std', float),
        ('is_on_clickstream', bool)
    ]
    for key, value_type in key_value_types:
        validate_dict_value_type(benchmark_result, key, value_type)


def parse_benchmark_results(benchmark_results):
    auc, auc_on_cs = {}, {}
    std, std_on_cs = {}, {}

    for result_file in benchmark_results:
        with open(result_file) as f:
            benchmark_result = json.load(f)
            validate_benchmark_result_format(benchmark_result)
            dataset_name = benchmark_result['dataset_name']
            if benchmark_result['is_on_clickstream']:
                auc_on_cs[dataset_name] = benchmark_result['auc']
                std_on_cs[dataset_name] = benchmark_result['std']
            else:
                auc[dataset_name] = benchmark_result['auc']
                std[dataset_name] = benchmark_result['std']

    return auc, std, auc_on_cs, std_on_cs


def format_auc_std(title, auc, std):
    table_rows = []
    for dataset_name in sorted(auc.keys()):
        table_rows.append('|| {dataset_name}| {auc}| {std}||'.format(
            dataset_name=dataset_name, auc=auc[dataset_name], std=std[dataset_name]
        ))

    message = dedent("""\
    {title}
    #|
    || dataset_name| auc| std||
    {table}
    |#""").format(title=title, table='\n'.join(table_rows))
    return message


def prepare_st_message(description, auc, std, auc_on_cs, std_on_cs):
    return dedent("""\
    **Benchmark resutls**
    {description}

    {auc_std}

    {auc_std_on_cs}
    """).format(
        description=description,
        auc_std=format_auc_std('On full dataset', auc, std),
        auc_std_on_cs=format_auc_std('On clickstream', auc_on_cs, std_on_cs)
    )


@vh.lazy.hardware_params(vh.HardwareParams(max_ram=1024))
@vh.lazy(
    object,
    benchmark_results=vh.mkinput(vh.File, nargs='*'),
    st_token=vh.mkoption(vh.Secret),
    ticket=vh.mkoption(str),
    description=vh.mkoption(str),
    useragent=vh.mkoption(str, default='robot-xprod'),
    base_url=vh.mkoption(str, default='https://st-api.yandex-team.ru/v2'),
)
def process_bm_results(benchmark_results, st_token, ticket, description, useragent,
                       base_url):
    nirvana_logger.info('Began processing benchmark resutls')
    assert len(benchmark_results) > 0, 'No benchmark results provided!'

    auc, std, auc_on_cs, std_on_cs = parse_benchmark_results(benchmark_results)
    message = prepare_st_message(description, auc, std, auc_on_cs, std_on_cs)

    st_client = Startrek(useragent=useragent, base_url=base_url, token=st_token.value)
    st_issue = st_client.issues[ticket]
    st_issue.comments.create(text=message)

    return {
        'auc': auc,
        'std': std,
        'auc_on_cs': auc_on_cs,
        'std_on_cs': std_on_cs
    }

    nirvana_logger.info('Benchmark resutls processed!')


@vh.lazy.hardware_params(vh.HardwareParams(max_ram=1024))
@vh.lazy(
    processed_gs_results=vh.mkoutput(vh.File),
    gs_results=vh.mkinput(vh.File),
    dataset_name=vh.mkoption(str),
    is_on_clickstream=vh.mkoption(bool),
)
def process_gs_results(gs_results, dataset_name, is_on_clickstream, processed_gs_results):
    nirvana_logger.info('Began processing gs resutls')

    with open(gs_results, 'r') as gs_res_fd:
        gs_results_dict = json.loads(gs_res_fd.read())

    with open(processed_gs_results, 'w') as out:
        out.write(json.dumps({
            'dataset_name': dataset_name,
            'is_on_clickstream': is_on_clickstream,
            'auc': gs_results_dict['mean_val'],
            'std': gs_results_dict['std_val'],
        }))

    nirvana_logger.info('Gs resutls processed!')
