from six import string_types
import datetime
import yt.wrapper as yt_wrapper
from datacloud.config import yt as yt_config_path
from datacloud.model_applyer.lib.features_list import all_features


class ModelConfig(object):
    def __init__(self,
                 score_name,
                 partner_id,
                 required_features,
                 local_binary_path=None,
                 is_local=False,
                 date_str=None,
                 model_class=None,
                 is_save_info=False):
        self.score_name = score_name
        self.partner_id = partner_id
        self.required_features = required_features
        self.is_local = is_local
        if self.is_local:
            assert local_binary_path, 'To use is_local please set binary_path to local path to model binary.'
            self.binary_path = local_binary_path
        else:
            self.binary_path = yt_wrapper.ypath_join(yt_config_path.PARTNER_BINARY_MODEL_YT_PATH, self.partner_id, self.score_name, 'current')
        self.model_class = model_class
        self.date_str = date_str or datetime.datetime.now().strftime('%Y-%m-%d')
        self.current_score_table = yt_wrapper.ypath_join(yt_config_path.MODELS_FOLDER, self.partner_id, self.score_name, 'current')
        self.score_dir = yt_wrapper.ypath_join(yt_config_path.MODELS_FOLDER, self.partner_id, self.score_name)
        self.tmp_dir = yt_wrapper.ypath_join(yt_config_path.UNRELIABLE_TMP_FOLDER, self.partner_id, self.score_name, self.date_str)
        self.is_save_info = is_save_info

    @staticmethod
    def from_json(json_data):
        partner_id = json_data['partner_id']
        score_name = json_data['score_name']
        binary_path = json_data.get('binary_path', '')
        is_local = json_data.get('is_local', False)
        is_save_info = json_data.get('save_info', False)

        str_required_features = json_data['features']
        required_features = []

        if isinstance(str_required_features, string_types):
            str_required_features = str_required_features.split()

        for str_feature in str_required_features:
            # requied_features.append(all_features[feature])
            required_features.append(_parse_feature(str_feature))
        return ModelConfig(
            score_name, partner_id, required_features,
            binary_path, is_local=is_local, is_save_info=is_save_info)

    def __str__(self):
        return ' '.join([self.score_name, self.partner_id, str(self.required_features), self.binary_path])


def _parse_feature(str_feature):
    if ':' in str_feature:
        parts = str_feature.split(':')
        assert len(parts) == 2
        feature, param = parts[0], parts[1]
        assert feature in all_features
        assert param and param[0] == 'f'
        default = float(param[1:])
        return all_features[feature](default=default)
    else:
        feature = str_feature
        assert feature in all_features
        return all_features[feature]()
