# -*- coding: utf-8 -*-
from copy import deepcopy
import pandas as pd
from benchmarking import calculate_bench_table, calculate_comp_table, calculate_yoy_table, prepare_dyn_table
from grouped_tables import calculate_grouped_table, calculate_rating, prepare_grouped_table
from utils import filter_by_date, fill_empty_df, fill_client_comp_columns, fill_with_dashes


def create_bench_tables_by_places(task, data_df, *opt):
    column, params = opt
    formula = params.get('formula')

    cols = [formula['divinded'], formula['devider']] if formula else [column]
    for col in task.filter_by.values():
        if col not in cols:
            cols.append(col)

    data_df = (data_df.loc[:, ['Date', 'Client', 'Place', 'Device'] + cols].copy()
               .groupby(['Date', 'Client', 'Place', 'Device'], as_index=False)
               .sum()
               )
    data_df = fill_client_comp_columns(task.client, data_df, cols)

    tables, dyn_tables = [], []
    target_columns = []
    for prefix, place, target_row_num in zip(['Total', 'Search', 'Networks'],
                                             [None, [u'Поиск'], [u'Сети']],
                                             [4, 16, 28]):
        tmp_data_df = data_df[data_df['Place'].isin(place)] if place else data_df.copy()

        for i, fn in enumerate([calculate_bench_table, calculate_yoy_table], 1):
            df = fn(task, tmp_data_df.copy(), column, formula)

            if i == 1:
                df = df.rename(columns={
                    'Client%s' % column: '%sClient%s' % (prefix, column),
                    'Comp%s' % column: '%sComp%s' % (prefix, column),
                    'CompMin': '%sCompMin%s' % (prefix, column),
                    'CompMax': '%sCompMax%s' % (prefix, column)
                })
                target_columns += get_place_columns(place=prefix, metric=column)
                dyn_tables.append(df)

            elif i == 2:
                setattr(df, 'descr', {
                    'position': {'row': target_row_num, 'column': 18},
                    'columns': [u'Period', 'Client%s' % column, 'Comp%s' % column, u'CompMin', u'CompMax']
                })
                tables.append(df)

                if column in ['CR', 'CPA']:
                    notes_df = fill_with_dashes(task, df.copy(), column)
                    setattr(notes_df, 'descr', {
                        'position': {'row': target_row_num, 'column': 25},
                        'columns': [u'Period', 'Client%s' % column, 'Comp%s' % column]
                    })
                    tables.append(notes_df)

        df = calculate_grouped_table(task, tmp_data_df.copy(), *opt, group_by='Device')[0]
        descr = {
            'position': {'row': target_row_num + 5, 'column': 18},
            'columns': ['Device', 'Client%s' % column, 'Comp%s' % column, 'CompSum'] if formula is None else
                       ['Device', 'Client%s' % column, 'Comp%s' % column]
        }
        setattr(df, 'descr', descr)
        tables.append(df)

        if column in ['CR', 'CPA']:
            notes_df = fill_with_dashes(task, df.copy(), column)
            descr = {
                'position': {'row': target_row_num + 5, 'column': 25},
                'columns': ['Device', 'Client%s' % column, 'Comp%s' % column]
            }
            setattr(notes_df, 'descr', descr)
            tables.append(notes_df)

    df = pd.concat([df_.set_index([u'Date', u'PrettyDate']) for df_ in dyn_tables], axis='columns').reset_index()
    setattr(df, 'descr', {
        'position': {'row': 4, 'column': 1},
        'columns': [u'Date', u'PrettyDate'] + target_columns
    })
    tables.append(df)

    return tables


def fin_types_sheet(task, data_df, *opt):
    column, params = opt
    formula = params.get('formula')
    cols = [formula['divinded'], formula['devider']] if formula else [column]

    data_df = fill_client_comp_columns(task.client, data_df.copy(), cols)

    tables = []
    for table in task.config['tables']:
        group_by = table.get('group_by')
        df = calculate_grouped_table(task, data_df, *opt, group_by=group_by, place=table.get('Place'))[0]
        if column in ['CR', 'CPA']:
            notes_df = fill_with_dashes(task, df.copy(), column)

        df = prepare_grouped_table(df, column, formula, group_by, group_names=table.get('group_names'))

        if column in ['CR', 'CPA']:
            descr = deepcopy(table.get('descr'))
            if group_by == 'Place':
                descr['position']['column'] += 4
            else:
                descr['position']['row'] += 42
            descr['columns'] = [group_by, 'Client%s' % column, 'Comp%s' % column]
            setattr(notes_df, 'descr', descr)
            tables.append(notes_df)

        descr = table.get('descr')
        descr['columns'] = [group_by, 'Client%s' % column, 'Comp%s' % column]
        if table.get('group_names'):
            descr['columns'].insert(1, '%s_2' % group_by)
        if not formula:
            descr['columns'] += ['CompSum', 'ClientShares', 'CompShares']
        setattr(df, 'descr', descr)
        tables.append(df)

    return tables


def fin_competitors_sheet(task, data_df):
    tables = []
    for place, p1_col_num, p2_col_num in zip([None, [u'Поиск'], [u'Сети']], [1, 4, 7], [12, 19, 26]):
        tmp_data_df = data_df[data_df['Place'].isin(place)].copy() if place else data_df.copy()

        df = calculate_rating(task, filter_by_date(tmp_data_df.copy(), task.periods['period_1']),
                              sort_by=task.target, other=True)
        setattr(df, 'descr', {
            'position': {'row': 4, 'column': p1_col_num},
            'columns': ['Client', task.target]
        })
        tables.append(df)

        df = calculate_rating(task, filter_by_date(tmp_data_df.copy(), task.periods['period_2']),
                              sort_by=task.target, other=True)
        setattr(df, 'descr', {
            'position': {'row': 4, 'column': p2_col_num},
            'columns': ['Client', 'DirectClicks', task.target, 'DirectCost', 'CPA', 'CR']
        })
        tables.append(df)

    return tables


def fin_overview_sheet(task, data_df):
    df = (data_df.copy()[data_df['Client'] != task.client]
          .loc[:, ['Date', 'Place', 'Client', 'DirectClicks', task.target]]
          .groupby(['Date', 'Place', 'Client'], as_index=False).sum()
          )

    if df.empty:
        dates = data_df['Date'].values.tolist()
        df = fill_empty_df({
            'Date': dates,
            'Client': [None, ] * len(dates),
            'Place': [None, ] * len(dates),
            'DirectClicks': [0, ] * len(dates),
            task.target: [0, ] * len(dates)
        })

    for place, condition in zip(['Search', 'Networks'], [u'Поиск', u'Сети']):
        df['%sClicks' % place] = df.apply(
            lambda row: row['DirectClicks'] if row['Place'] == condition else 0, axis=1)
        df['%s%s' % (place, task.target)] = df.apply(
            lambda row: row[task.target] if row['Place'] == condition else 0, axis=1)

    df = df.groupby(['Date', 'Client'], as_index=False).sum()
    df = df.groupby('Date', as_index=False).agg({
        'DirectClicks': pd.np.count_nonzero,
        task.target: pd.np.count_nonzero,
        'SearchClicks': pd.np.count_nonzero,
        'Search%s' % task.target: pd.np.count_nonzero,
        'NetworksClicks': pd.np.count_nonzero,
        'Networks%s' % task.target: pd.np.count_nonzero
    })
    df = prepare_dyn_table(task, df)

    setattr(df, 'descr', {
        'position': {'row': 4, 'column': 1},
        'columns': ['Date', 'PrettyDate', 'DirectClicks', task.target, 'SearchClicks', 'Search%s' % task.target,
                    'NetworksClicks', 'Networks%s' % task.target]
    })

    return df


def fin_target_share_dynamics(task, data_df, place):
    data_df = data_df[data_df['Place'].isin(place)] if place else data_df.copy()
    data_df = calculate_comp_table(task, data_df.loc[:, ['Date', 'Client', task.target]], task.target, None,
                                   filter_client=False).set_index(['Date', 'PrettyDate'])

    data = []
    other = False
    for idx, row in data_df.iterrows():
        tmp_data = list(idx)  # Тут лежат Date и PrettyDate

        try:
            cli_value = row[task.client]
            cli_share = cli_value / float(row.sum())

        except KeyError:
            cli_share = 0.0
        except ZeroDivisionError:
            cli_share = 0.0
        tmp_data += [cli_share]

        comp_values = row[[comp for comp in row.index if comp != task.client]].values.tolist()
        try:
            comp_shares = [val / float(row.sum()) for val in comp_values]
        except ZeroDivisionError:
            comp_shares = [0.0] * len(comp_values)
        comp_shares.sort(reverse=True)

        if len(comp_shares) > 20:
            other_share = sum(comp_shares[-len(comp_shares) + 20:])
            comp_shares = comp_shares[:20] + [other_share]
            if not other:
                other = True
                comp_names = [u'Конкурент {}'.format(i) for i in range(1, 21)] + [u'Прочие конкуренты']

        tmp_data += comp_shares

        data.append(tmp_data)

    if not other:
        comp_names = [u'Конкурент {}'.format(i) for i in range(1, len(data[0]) - 2)]

    df = pd.DataFrame(data, columns=['Date', 'PrettyDate', task.client] + comp_names).fillna(0.)

    setattr(df, 'descr', {
        'position': {'row': 2, 'column': 1},
        'columns': ['Date', 'PrettyDate'] + [col for col in df.columns if col not in ['Date', 'PrettyDate']],
        'draw_column_names': True
    })
    return df


def categories_sheet(task, data_df):
    data_df = filter_by_date(data_df.copy(), task.periods['period_2'])
    data_df = data_df[data_df['Client'].isin([task.client])]
    df = (data_df.groupby('Category', as_index=False).sum()
          .sort_values(by='DirectCost', ascending=False)
          .reset_index(drop=True)
          )
    setattr(df, 'descr', {
        'position': {'row': 3, 'column': 1},
        'columns': [u'Category', u'DirectClicks', task.target, u'DirectCost']
    })
    return df


def get_place_columns(place, metric):
    columns = ['Client', 'Comp', 'CompMin', 'CompMax']
    columns = ['{place}{column}{metric}'.format(place=place, column=column, metric=metric) for column in columns]

    return columns
