import re
from datacloud.dev_utils.logging.logger import get_basic_logger
from datacloud.dev_utils.status_db.task import Status
from datacloud.dev_utils.yt.yt_utils import get_yt_client
from datacloud.dev_utils.solomon.solomon_utils import str2ts, post_sensors_to_solomon_by_batches
from collections import Counter

from datacloud.dev_utils.time.patterns import RE_DAILY_LOG_FORMAT, RE_5MIN_LOG_FORMAT

logger = get_basic_logger(__name__)

FAST_LOGS_PROJECT = 'datacloud'
FAST_LOGS_CLUSTER = 'datacloud_score'
FAST_LOGS_SERVICE = 'datacloud_api-fastlogs'
INPUT_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S+00:00'

FAST_LOGS_YT_STREAM_FOLDER = '//home/x-products/production/services/logs/datacloud_score_api/fast_logs/clean/stream'
FAST_LOGS_YT_HISTORY_FOLDER = '//home/x-products/production/services/logs/datacloud_score_api/fast_logs/clean/history'


def read_record(rec):
    scores = rec['req_body']['scores']
    answer = rec['resp_body']
    score_names = []
    for score in scores:
        score_names.append(score['score_name'])
    scores_hit = {}
    if rec['status'] != '200':
        for score_name in score_names:
            scores_hit[score_name] = 'timeout'
    else:
        for score in answer['scores']:
            scores_hit[score['score_name']] = score['has_score']

    for score_name in score_names:
        yield {
            'partner_id': rec['partner_id'],
            'status': rec['status'],
            'timestamp': str2ts(rec['timestamp'], INPUT_TIME_FORMAT),
            'score_name': score_name,
            'has_score': str(scores_hit[score_name])
        }


def read_score_reqs_from_table(yt_client, log_table_path):
    for rec in yt_client.read_table(log_table_path):
        if rec['req_type'] == 'scores':
            for score_info in read_record(rec):
                yield score_info


def count_records(yt_client, log_table_path):
    sensors_reqs_counter = Counter()
    keys = None
    for score_req in read_score_reqs_from_table(yt_client, log_table_path):
        sensors_reqs_counter[tuple(score_req.values())] += 1
        if keys is None:
            keys = score_req.keys()
    return sensors_reqs_counter, keys


def counter2sensors(score_reqs_counter, keys):
    for labels, value in score_reqs_counter.items():
        yield {
            'labels': {key: label for key, label in zip(keys, labels) if key != 'timestamp'},
            'ts': labels[keys.index('timestamp')],
            'value': value
        }


def send_fast_logs_to_solomon(yt_client, log_table_path):
    logger.info('Sending logs to solomon from table: \n\t{}'.format(log_table_path))
    sensors = list(counter2sensors(*count_records(yt_client, log_table_path)))
    post_sensors_to_solomon_by_batches(
        FAST_LOGS_PROJECT,
        FAST_LOGS_CLUSTER,
        FAST_LOGS_SERVICE,
        sensors
    )
    logger.info('Logs sent!')


def upload_to_solomon(task):
    log_table_path = task.data['table_path']
    yt_client = get_yt_client()
    logger.info(' Start upload table: \n\t{}'.format(log_table_path))
    log_folder = '/'.join(log_table_path.split('/')[:-1])

    last_table = yt_client.list(log_folder, absolute=True)[-1]
    if not yt_client.exists(log_table_path):
        logger.warn('There is no input table on YT {}'.format(log_table_path))
        return [task.make_done(new_status=Status.SKIPPED)]

    send_fast_logs_to_solomon(yt_client, log_table_path)
    if log_table_path.split('/')[-2] == 'history' or last_table != log_table_path:
        return [task.make_done()]
    return []


def detect_ready(date_time, days=None):
    yt_client = get_yt_client()
    for table in yt_client.list(FAST_LOGS_YT_STREAM_FOLDER, absolute=True):
        date = table.split('/')[-1]
        if re.match(RE_5MIN_LOG_FORMAT, date):
            yield table, {'table_path': table}
    for table in yt_client.list(FAST_LOGS_YT_HISTORY_FOLDER, absolute=True):
        date = table.split('/')[-1]
        if re.match(RE_DAILY_LOG_FORMAT, date):
            yield table, {'table_path': table}
