# -*- coding: utf-8 -*-
import logging
import pandas as pd
from make_data.make_queries import get_query_txt
from make_data.yql_worker import YQLWorker
from utils import decode_cell, parse_list

logger = logging.getLogger(__name__)


def prepare_task_df(cpa_task, task_df):
    task_df['Client'] = task_df['Client'].apply(
        lambda value: str(value).strip() if isinstance(value, int) else value.strip())
    for col in ['CounterID', 'GoalID', 'ClientID', 'CampaignID']:
        task_df[col] = task_df[col].apply(lambda cell: parse_list(cell))

    if cpa_task.type_ == 'standard':
        task_df = fill_clients_from_ca(cpa_task, task_df)

    elif cpa_task.type_ == 'yt_registry':
        task_df = fill_clients_from_mapping(cpa_task, task_df)

    task_df = task_df.drop_duplicates()
    task_df['DomainID'] = [''] * len(task_df.index)
    if cpa_task.domain_filters:
        task_df = fill_domain_ids(cpa_task, task_df)

    return task_df


def fill_domain_ids(cpa_task, task_df):
    logger.info('%s: fill DomainID from TargetDomain', cpa_task.issue.key)

    task_query = get_query_txt('get_domids').format(**{
        'login': cpa_task.issue.createdBy.login,
        'issue_key': cpa_task.issue.key,
        'domains': u'\n'.join(list(task_df['Client'].unique()))
    })
    task_worker = YQLWorker(cpa_task, task_query, result_names=['domains'])
    task_worker.run()

    rows_to_drop = []
    for idx, client in task_df.iterrows():
        task_df.loc[idx, 'DomainID'] = join_client_params(task_worker.dfs['domains'], client['Client'], 'DomainID')

        if not task_df.loc[idx, 'DomainID']:
            logger.warning(u'{}: {} not in TargetDomain'.format(cpa_task.issue.key, client['Client']))
            rows_to_drop.append({'id': idx, 'Client': client['Client'], 'Category': client['Category']})

    if rows_to_drop:
        cpa_task.comment += [u'<{По некоторым клиентам из задания не найдены DomainID:'] + \
                            [u'* {}, {}'.format(row['Client'], row['Category']) for row in rows_to_drop] + [u'}>'] + \
                            [u'Возможно, в колонке **Бренд/Домен** указаны не домены или они указаны некорректно.\n']
        task_df = task_df.drop(labels=[row['id'] for row in rows_to_drop], axis='index').reset_index()

    return task_df


def fill_clients_from_ca(cpa_task, task_df):
    logger.info('%s: fill ClientID from BannerIDClient', cpa_task.issue.key)

    clients_to_fill = task_df.loc[(task_df['ClientID'] == '') & (task_df['CampaignID'] == '')]
    clients_to_fill = u'\n'.join(list(clients_to_fill['Client'].unique()))
    if clients_to_fill:
        task_query = get_query_txt('get_clids').format(**{
            'login': cpa_task.issue.createdBy.login,
            'issue_key': cpa_task.issue.key,
            'clients': clients_to_fill,
            'field': 'Client' if cpa_task.categorization['use_domain_sets'] else 'Domain'
        })
        task_worker = YQLWorker(cpa_task, task_query, result_names=['clids'])
        task_worker.run()
    else:
        task_worker = YQLWorker
        setattr(task_worker, 'dfs', {'clids': pd.DataFrame()})

    rows_to_drop = []
    for idx, client in task_df.iterrows():
        if not client['ClientID'] and not client['CampaignID']:
            task_df.loc[idx, 'ClientID'] = join_client_params(task_worker.dfs['clids'], client['Client'], 'ClientID')

        if not task_df.loc[idx, 'ClientID'] and not client['CampaignID']:
            logger.warning(u'{}: {} not in BannerIDClient'.format(cpa_task.issue.key, client['Client']))
            rows_to_drop.append({'id': idx, 'Client': client['Client'], 'Category': client['Category']})

    if rows_to_drop:
        cpa_task.comment += [u'<{По некоторым клиентам из задания не найдены ClientID:'] + \
                            [u'* {}, {}'.format(row['Client'], row['Category']) for row in rows_to_drop] + [u'}>'] + \
                            [u'Возможно, **Бренд/Домен** указаны некорректно или не выбрана опция '
                             u'**Использовать связки доменов**.\n']
        task_df = task_df.drop(labels=[row['id'] for row in rows_to_drop], axis='index').reset_index()

    return task_df


def fill_clients_from_mapping(cpa_task, task_df):
    logger.info('%s: fill CounterID, GoalID, ClientID from mapping', cpa_task.issue.key)
    task_query = get_query_txt('get_mapping').format(**{
        'login': cpa_task.issue.createdBy.login,
        'issue_key': cpa_task.issue.key,
        'clients': u'\n'.join(list(task_df['Client'].unique())),
        'categories': u'\n'.join(list(task_df['Category'].unique()))
    })
    task_worker = YQLWorker(cpa_task, task_query, result_names=['goals', 'campaigns'])
    task_worker.run()
    for table in ['goals', 'campaigns']:
        for col_name in ['Client', 'Category']:
            task_worker.dfs[table][col_name] = task_worker.dfs[table][col_name].apply(lambda cell: decode_cell(cell))

    rows_to_drop = []
    for idx, client in task_df.iterrows():
        for table_key in ['CounterID', 'GoalID']:
            task_df.loc[idx, table_key] = join_client_params(
                task_worker.dfs['goals'], client['Client'], table_key, category=client['Category'])
        task_df.loc[idx, 'CampaignID'] = join_client_params(
            task_worker.dfs['campaigns'], client['Client'], 'CampaignID', category=client['Category'])

        if not task_df.loc[idx, 'CounterID'] or not task_df.loc[idx, 'CampaignID']:
            logger.warning(u'{}: {}, {} not in mapping'.format(cpa_task.issue.key, client['Client'], client['Category']))
            rows_to_drop.append({'id': idx, 'Client': client['Client'], 'Category': client['Category']})

    if rows_to_drop:
        cpa_task.comment += [u'<{По некоторым клиентам из задания не найдены CounterID или CampaignID:'] + \
                            [u'* {}, {}'.format(row['Client'], row['Category']) for row in rows_to_drop] + [u'}>'] + \
                            [u'Возможно, **Клиент/Категория** указаны некорректно.\n']
        task_df = task_df.drop(labels=[row['id'] for row in rows_to_drop], axis='index').reset_index()

    return task_df


def join_client_params(from_df, client, table_key, category=None):
    params = []
    for i, row in from_df.iterrows():
        if category:
            if row['Client'] == client and row['Category'] == category:
                params.append(row[table_key])

        else:
            if row['Client'] == client:
                params.append(row[table_key])

    return ', '.join([str(param) for param in list(set(params))])


def parse_rules(rules_df):
    client_rules = {}
    for idx, row in rules_df.iterrows():
        client = row['Client']
        rule = row['Rule']
        if isinstance(rule, int) or isinstance(rule, float):
            rule = str(int(rule))

        if not client_rules.get(client):
            client_rules[client] = {'default': 'other', 'rules': []}

        if rule == '':
            client_rules[client]['default'] = row['Category']
            continue

        else:
            tokens = rule.split(' -', 1)
            words = tokens[0].lower().split()
            minus_words = []
            if len(tokens) > 1:
                minus_words = tokens[1].lower().split(' -')
            client_rules[client]['rules'].append({
                'words': words, 'minus-words': minus_words, 'category': row['Category']})

    return client_rules
