# -*- coding: utf-8 -*-
import logging
from os.path import dirname, join
import pandas as pd

from exceller import ExcelDocument
from calculations.retail_tables import categories_table, retail_bench_tables, retail_place_device_tables
from calculations.utils import get_gain
from cpa_task.utils import convert_name
from xlsx_worker import fill_info_ws, rng_formula_to_address, write_df

logger = logging.getLogger(__name__)


def retail_report(task, df, region, category, **kwargs):
    report_name = u'{f_num}_{client}_{region}_{cat}.xlsx'.format(
        f_num=kwargs.get('f_num'), client=task.client, region=region['region_name'], cat=category)
    report_path = join(dirname(dirname(__file__)), report_name)
    logger.info(u'%s: make %s' % (task.issue.key, report_name))

    if category == u'Суммарные данные':
        setattr(task, 'categories_order', task.get_groupby_order(region['region_ids']))

    if few_competitors(task, df):
        logger.warning(u'%s: few competitors in %s' % (task.issue.key, report_name))
        task.few_competitors += [u'* !!(yellow)%s!!' % report_name]

    report = ExcelDocument(join(dirname(dirname(__file__)), 'templates', task.config['xlsx_template']))
    report = retail_template_cleaner(
        [calculation['sheet_name'] for calculation in task.calculations.values()],
        report)

    for metric, params in task.calculations.iteritems():
        ws = report[params['sheet_name']]

        [func(ws, task, df, metric, params) for func in get_metric_funcs(metric)]

        rngs1 = [u'Periods', u'Client', u'Average', u'Max', u'Min']
        rngs1 = [u'{}_{}'.format(params.get('rng_pref', metric), x) for x in rngs1]
        rng_formula_to_address(report[params['sheet_name']], rngs1, range(2, 7), 3)

        rngs2 = [u'Cats', u'ClientCats', u'CompCats']
        rngs2 = [u'{}_{}'.format(params.get('rng_pref', metric), x) for x in rngs2]
        rng_formula_to_address(ws, rngs2, range(8, 11), 8)

        write_retail_gains(ws)
        for addr in ['C2', 'I2', 'I7', 'M7', 'Q7']:
            ws[addr].text = task.client

        rng_formula_to_address(ws, rngs2, range(8, 11), 8)

    info = {'B9': u'Да' if task.ecom else u'Нет',
            'B14': convert_name(task.target, task.config['Targets'], to_local=False),
            'B20': task.client,
            'B25': category,
            'M4': region['region_name'],
            'B31': task.time_detail,
            'B36': task.period['first_date'].strftime('%Y-%m-%d'),
            'D36': task.period['last_date'].strftime('%Y-%m-%d'),

            'B41': task.periods['period_1']['first_date'].strftime('%Y-%m-%d'),
            'C41': task.periods['period_1']['last_date'].strftime('%Y-%m-%d'),

            'D41': task.periods['period_2']['first_date'].strftime('%Y-%m-%d'),
            'E41': task.periods['period_2']['last_date'].strftime('%Y-%m-%d'),

            'B47': task.currency
            }
    fill_info_ws(report['Info'], task, info, region)

    report.update_charts_cache(named_to_simple_ranges=True)
    report.save(report_path)

    return report_path


def few_competitors(task, data_df):
    col = 'EcommerceOrderVisits' if task.ecom else task.target

    df = data_df.copy()[data_df['Client'] != task.client]

    df = df.groupby(['Date', 'Client'], as_index=False).sum()
    df = (df[['Date', col]] .groupby('Date', as_index=False)
          .agg({col: pd.np.count_nonzero})
          )

    if sum(df[col] < 3) != 0 or df.empty:
        return True
    else:
        return False


def retail_metric_builder(fn, **kwargs):
    def builder(ws, task, df, *opt):
        results = fn(task, df, *opt, **kwargs)
        [write_df(ws, res) for res in results if not res.empty]

    return builder


def get_metric_funcs(metric):
    funcs = [
        retail_metric_builder(retail_bench_tables),
        retail_metric_builder(categories_table)
    ]
    if metric not in ['CSR', 'ROI']:
        funcs += [
            retail_metric_builder(retail_place_device_tables, group_by='Place'),
            retail_metric_builder(retail_place_device_tables, group_by='Device')
        ]

    return funcs


def retail_template_cleaner(sheets, report):
    for ws in report:
        if ws.name == 'Info':
            for row in [9, 14, 20, 25, 31, 36, 41, 47]:
                ws.clear_value('B{0}:E{0}'.format(row))
            for rng in ['M4:N5', 'P5:R9']:
                ws.clear_value(rng)

        elif ws.name in sheets:
            for rng in ['A4:F17', 'I3:J4', 'H9:J10', 'L8:R9']:
                ws.clear_value(rng)
            for rng in ['C2', 'I2', 'H3:H4', 'K4', 'I5:J5', 'I7', 'M7', 'Q7']:
                if ':' not in rng:
                    rng = '{0}:{0}'.format(rng)
                ws.clear_contents(rng)

        else:
            clean_unused_ranges(ws)

    return report


def clean_unused_ranges(ws):
    if ws.name == u'Конверсии':
        pref = u'Orders'
    elif ws.name == u'Доходы':
        pref = u'Revenue'
    elif ws.name == u'ДРР':
        pref = u'CSR'
    elif ws.name == u'ROI':
        pref = u'ROI'

    for rng_name in [u'Periods', u'Client', u'Average', u'Max', u'Min', u'Cats', u'ClientCats', u'CompCats']:
        rng_name, addr = u'{}_{}'.format(pref, rng_name), u'\'{}\'!$A$1'.format(ws.name)
        ws.doc.set_named_range(rng_name, addr)

    for rng in ['A3:F17', 'I3:J4', 'H8:J10', 'L8:R9']:
        ws.clear_value(rng)

    for rng in ['C2', 'I2', 'H3:H4', 'K4', 'I5:J5', 'I7', 'M7', 'Q7']:
        if ':' not in rng:
            rng = '{0}:{0}'.format(rng)
        ws.clear_contents(rng)

    ws['B1'].text = u'Не участвует в расчете'

    return ws


def write_retail_gains(ws):
    ws.set_cell_value(5, 9, get_gain(ws['I4'], ws['I3']))
    ws.set_cell_value(5, 10, get_gain(ws['J4'], ws['J3']))
    ws.set_cell_value(4, 11, get_gain(ws['I4'], ws['J4']))

    return ws
