# -*- coding: utf-8 -*-
import re
from yt.wrapper import ypath_join, ypath_split
from datacloud.dev_utils.yt.yt_config_table import ConfigTable
from datacloud.dev_utils.yt.yt_utils import create_folders
from datacloud.dev_utils.time.patterns import RE_DAILY_LOG_FORMAT


__all__ = [
    'StabilityRecord',
    'DistStabMngr',
    'METAFEATURE_MONITORING_MANAGMENT_TABLE',
    'METAFEATURE_MONITORING_LOG_TABLE',
    'METAFEATURE_STABILITY_FOLDER',
    'METAFEATURE_MONITORING_LOG_TABLE_SCHEME'
]


STABILITY_FOLDER = '//home/x-products/production/datacloud/stability/feature_distribution_stability'
TEST_SCORE_STABILITY_FOLDER = ypath_join(STABILITY_FOLDER, 'new_score_daily_distributions')
# DISTRIB_STABILITY_CONFIG = '//home/x-products/production/datacloud/stability/feature_distribution_stability/metafeature_monitoring_control'
TMP_FOLDER = '//projects/scoring/tmp/prod-tmp/stability-scores'
METAFEATURE_STABILITY_FOLDER = '//home/x-products/production/datacloud/stability/feature_distribution_stability'
METAFEATURE_MONITORING_MANAGMENT_TABLE = ypath_join(METAFEATURE_STABILITY_FOLDER, 'metafeature_monitoring_control')
METAFEATURE_MONITORING_LOG_TABLE = ypath_join(METAFEATURE_STABILITY_FOLDER, 'metafeature_monitoring_log')
APPLIED_MODELS_FOLDER = '//home/x-products/production/datacloud/models'


METAFEATURE_MONITORING_MANAGMENT_TABLE_SCHEME = [
    {'name': 'partner_id', 'type': 'string', 'sort_order': 'ascending'},
    {'name': 'score_id', 'type': 'string', 'sort_order': 'ascending'},
    {'name': 'custom_path_to_distributions', 'type': 'string'},
    {'name': 'reference_distribution_table', 'type': 'string'},
    {'name': 'reference_distribution_table_segments', 'type': 'string'},
    {'name': 'path_to_feature_split_pickle', 'type': 'string'},
    {'name': 'path_to_clf_pickle', 'type': 'string'},
    {'name': 'is_active', 'type': 'boolean'},
    {'name': 'fixed_reference_table', 'type': 'boolean'},
    {'name': 'custom_bin_aggregation', 'type': 'any'},
    {'name': 'criterion', 'type': 'double'}
]

METAFEATURE_MONITORING_LOG_TABLE_SCHEME = [
    {'name': 'partner_id', 'type': 'string', 'sort_order': 'ascending'},
    {'name': 'score_id', 'type': 'string', 'sort_order': 'ascending'},
    {'name': 'date', 'type': 'string', 'sort_order': 'ascending'},
    {'name': 'segment_type', 'type': 'string', 'sort_order': 'ascending'},
    {'name': 'testing_mode', 'type': 'boolean', 'sort_order': 'ascending'},
    {'name': 'metafeature_psi_list', 'type': 'any'},
    {'name': 'criterion_check_list', 'type': 'any'},
    {'name': 'reference_table', 'type': 'string'},
    {'name': 'input_table', 'type': 'string'},
    {'name': 'score_application_date', 'type': 'string'}
]


class StabilityRecord(object):
    __slots__ = (
        'partner_id',
        'score_id',
        'features_table'
    )

    def __init__(
        self,
        partner_id=None,
        score_id=None,
        features_table=None
    ):
        self.partner_id = partner_id
        self.score_id = score_id
        self.features_table = features_table

    def to_json(self):
        return {
            'partner_id': self.partner_id,
            'score_id': self.score_id,
            'features_table': self.features_table
        }


class DistStabTable(ConfigTable):
    """
    Object for searching tables for monitroing
    which were mentioned in METAFEATURE_MONITORING_MANAGMENT_TABLE
    """
    def __init__(self):
        super(DistStabTable, self).__init__(METAFEATURE_MONITORING_MANAGMENT_TABLE, METAFEATURE_MONITORING_MANAGMENT_TABLE_SCHEME)

    def get_tables_for_monitoring(self):
        for rec in self.list_records():
            if rec['is_active']:
                for table in self.list_score_folder(rec['partner_id'], rec['score_id']):
                    date_str = table.rsplit('/', 1)[-1]
                    if re.match(RE_DAILY_LOG_FORMAT, date_str):
                        yield rec['partner_id'], rec['score_id'], table, date_str

    def list_score_folder(self, partner_id, score_id):
        return self._yt_client.list(ypath_join(APPLIED_MODELS_FOLDER, partner_id, score_id), absolute=True)


class DistStabMngr(DistStabTable):
    def __init__(self, stability_record, is_testing_mode=False):
        super(DistStabMngr, self).__init__()
        self.partner_id = stability_record.partner_id
        self.score_id = stability_record.score_id
        self.features_table_name = ypath_split(stability_record.features_table)[-1]

        self.is_testing_mode = is_testing_mode
        if self.is_testing_mode:
            self.root = TEST_SCORE_STABILITY_FOLDER
        else:
            self.root = STABILITY_FOLDER
        rec = self.get_config_rec()
        self.clf_yt_path = rec['path_to_clf_pickle']
        self.list_groups_yt_path = rec['path_to_feature_split_pickle']
        self.make_daily_stability_path()
        self.make_segment_stability_path()
        self.make_tmp_features_from_requests_folder()

    def get_config_rec(self):
        return self.get_record_by_params(
            {'partner_id': self.partner_id, 'score_id': self.score_id}
        )

    def make_daily_stability_path(self):
        if self.is_testing_mode:
            self.daily_stability_path = ypath_join(
                self.root,
                self.partner_id,
                self.score_id,
                self.features_table_name,
                'daily'
            )
        else:
            self.daily_stability_path = ypath_join(
                self.root,
                self.partner_id,
                self.score_id,
                'daily'
            )
        create_folders(self.daily_stability_path, self._yt_client)

    def make_segment_stability_path(self):
        if self.is_testing_mode:
            self.segment_stability_path = ypath_join(
                self.root,
                self.partner_id,
                self.score_id,
                self.features_table_name,
                'segment'
            )
        else:
            self.segment_stability_path = ypath_join(
                self.root,
                self.partner_id,
                self.score_id,
                'segment'
            )
        create_folders(self.segment_stability_path, self._yt_client)

    def make_tmp_features_from_requests_folder(self, is_testing_mode=True):
        self.features_from_requests_folder = ypath_join(
            TMP_FOLDER,
            'yesterday-requests-features',
            'test_' + str(self.is_testing_mode),
            self.partner_id,
            self.score_id
        )
        create_folders(self.features_from_requests_folder, self._yt_client)

    def make_features_from_requests_table_path(self, table_name):
        return ypath_join(self.features_from_requests_folder, table_name)

    def make_daily_distribution_table_path(self, table_name):
        return ypath_join(self.daily_stability_path, table_name)

    def make_segment_distribution_table_path(self, table_name):
        return ypath_join(self.segment_stability_path, table_name)
