# -*- coding: utf-8 -*-
import yt.wrapper as yt_wrapper
from yt.wrapper import ypath_join

from datacloud.dev_utils.solomon.solomon_utils import post_sensors_to_solomon, str2ts
from datacloud.dev_utils.logging.logger import get_basic_logger
from datacloud.config import yt as yt_path_config
from datacloud.stability.crypta_stability.tables import (
    config_table, api_log_table
)
from datacloud.stability.crypta_stability.constants import (
    DEFAULT_KEY, TMP_FOLDER, DEFAULT_TAG, API_EVENTS_TABLE,
    HASH_EMAIL_TO_CID_Q, HASH_PHONE_TO_CID_Q,
    SOLOMON_PROJECT, SOLOMON_CLUSTER, API_SERVICE
)
from datacloud.stability.crypta_stability.helpers import (
    EventsByDateMapper, count_external_id, JoinCidsFromScores,
    get_creation_date
)


logger = get_basic_logger(__name__)


@yt_wrapper.with_context
def reduce_train_by_cid(key, recs, context):
    cids = []
    for rec in recs:
        if context.table_index == 0 or context.table_index == 1:
            cids.append(rec['cid'])
        elif len(cids) > 0:
            for cid in cids:
                yield {
                    'external_id': rec['external_id'],
                    'id_value': key['id_value'],
                    'cid': cid,
                    'target': rec['target']
                }
        else:
            yield {
                'external_id': rec['external_id'],
                'id_value': key['id_value'],
                'cid': None,
                'target': rec['target']
            }


def upload_api_stable_to_solomon(partner_id, score_name, crypta_date, score_date, hit):
    sensors = [{
        'labels': {
            'partner_id': partner_id,
            'score_name': score_name,
            'score_date': score_date,
        },
        'ts': str2ts(crypta_date),
        'value': hit
    }]
    post_sensors_to_solomon(SOLOMON_PROJECT, SOLOMON_CLUSTER, API_SERVICE, sensors)


def check_api_stable(yt_client, tag=DEFAULT_TAG, key=DEFAULT_KEY):
    with yt_client.Transaction(), yt_client.TempTable(TMP_FOLDER) as temp_table, \
            yt_client.TempTable(TMP_FOLDER) as score_temp_table:

        yt_client.run_map(
            EventsByDateMapper(),
            API_EVENTS_TABLE,
            temp_table,
            spec={'title': '[{}] filter events'.format(tag)}
        )

        eids_count_input = count_external_id(yt_client, temp_table, key=key)

        yt_client.run_sort(
            temp_table,
            sort_by='id_value',
            spec={'title': '[{}] filter events / sort after'.format(tag)}
        )

        yt_client.run_join_reduce(
            reduce_train_by_cid,
            [
                yt_client.TablePath(HASH_EMAIL_TO_CID_Q, attributes={'foreign': True}, columns=['id_value', 'cid']),
                yt_client.TablePath(HASH_PHONE_TO_CID_Q, attributes={'foreign': True}, columns=['id_value', 'cid']),
                yt_client.TablePath(temp_table, attributes={'primary': True})
            ],
            temp_table,
            reduce_by='id_value',
            join_by='id_value',
            spec={
                'title': '[{}] replace id_value by cid'.format(tag),
                'use_columnar_statistics': True
            }
        )
        yt_client.run_sort(
            temp_table,
            sort_by='cid',
            spec={'title': '[{}] replace id_value by cid / sort after'.format(tag)}
        )

        crypta_date = get_creation_date(yt_client, HASH_EMAIL_TO_CID_Q)
        log_table = api_log_table.CryptaStabilityLogTable()

        success = True
        config_recs = config_table.CryptaStabilityConfigTable().list_records()
        for config_rec in config_recs:
            current_score_path = ypath_join(
                yt_path_config.MODELS_FOLDER,
                config_rec['partner_id'],
                config_rec['score_name'],
                'current'
            )

            last_score = yt_client.TablePath(
                current_score_path,
                attributes={'columns': ['cid'], 'foreign': True}
            )
            events_by_cid = yt_client.TablePath(
                temp_table,
                attributes={'columns': ['cid', key], 'primary': True}
            )
            yt_client.run_join_reduce(
                JoinCidsFromScores(),
                [last_score, events_by_cid],
                score_temp_table,
                reduce_by='cid',
                join_by='cid',
                spec={
                    'title': '[{}] events with score {}'.format(tag, config_rec['score_name']),
                    'use_columnar_statistics': True
                }
            )

            eids_count = count_external_id(yt_client, score_temp_table, key=key)

            score_date = yt_client.get_attribute(current_score_path, 'key')

            hit = float(eids_count) / eids_count_input
            logger.info('Calculated {parnter_id} {score_name}. Hit is {hit}'.format(
                parnter_id=config_rec['partner_id'],
                score_name=config_rec['score_name'],
                hit=hit
            ))
            cur_success = (hit >= config_rec['min_hit'])
            log_table.add_record(
                partner_id=config_rec['partner_id'],
                score_name=config_rec['score_name'],
                crypta_date=crypta_date,
                score_date=score_date,
                eids_count_input=eids_count_input,
                eids_count=eids_count,
                hit=hit,
                success=cur_success
            )
            upload_api_stable_to_solomon(
                partner_id=config_rec['partner_id'],
                score_name=config_rec['score_name'],
                crypta_date=crypta_date,
                score_date=score_date,
                hit=hit
            )

            success = success and cur_success

    return success
