# coding: utf-8
from copy import deepcopy
from datetime import datetime
import logging
from math import ceil
from os.path import dirname, join
from pptx import Presentation
import xlrd
import yaml

from . import PPTX_YML, return_pptx_name
from .pptx_slides import add_slide
from ..configure_reports import return_report_name, return_sheet_name


def make_ta_pptx(reports):
    """
    reports = {
        'search_queries': {'path': 'search_queries_path.xlsx'),
        'keywords': 'keywords_path.xlsx'
    }

    :param reports:
    :return:
    """
    logging.info('presentation')
    reports = get_reports_pptx_config(reports)
    if not reports:
        logging.info('empty presentation')
        return
    slides = get_genaral_pptx_config(reports)
    pptx = Presentation(join(dirname(__file__), u'%s.pptx' % PPTX_YML['presentation']['meta']['template_name']))

    chapter = 0
    for section_name in ['title', 'search_queries', 'keywords', 'closing']:
        if section_name not in ['search_queries', 'keywords']:
            for slide_name in PPTX_YML['presentation'][section_name]:
                add_slide(pptx, slides[section_name][slide_name])

        else:
            for sl_yml in reports.get(section_name, {}).get('slides', []):
                if sl_yml['layout'] == 'Spacer':
                    chapter += 1
                    sl_yml['text_holders']['text_num'] = u'%02d' % chapter

                add_slide(pptx, sl_yml)

    pptx.save(u'./%s.pptx' % return_pptx_name())
    logging.info('presentation created')
    return


def get_reports_pptx_config(reports):
    for report_name in reports.keys():
        try:
            wb = xlrd.open_workbook('%s.xlsx' % return_report_name(report_name), on_demand=True)
            if return_sheet_name(report_name, '_Review') not in wb.sheet_names():
                del reports[report_name]

            else:
                reports = fill_report_params(reports, report_name, wb)
                reports = get_report_slides(reports, report_name, wb)

        except IOError:
            del reports[report_name]

    return reports


def get_genaral_pptx_config(reports):
    with open(join(dirname(__file__), 'pptx_config.yml')) as fd:
        pptx_yml = yaml.load(fd)

    total_params = {
        'report_date': get_pretty_period(datetime.today()),
        'client': reports[reports.keys()[0]]['params']['client'].lower(),
        'currency': reports[reports.keys()[0]]['params']['currency'],
    }

    slides = {}
    for section_name in ['title', 'closing']:
        slides[section_name] = {}
        for slide_name in pptx_yml['presentation'][section_name]:
            sl_yml = deepcopy(pptx_yml['slides'][slide_name])
            sl_yml = format_sl_yml(sl_yml, **total_params)

            if slide_name == 'contents':
                chapter = 0
                for report_name in ['search_queries', 'keywords']:
                    if reports.get(report_name, {}).get('slides', []):
                        chapter += 1
                        sl_yml['text_holders']['text_num_%i' % chapter] = u'%02d' % chapter
                        sl_yml['text_holders']['text_%i' % chapter] = reports[report_name]['params']['report_name']

            slides[section_name][slide_name] = sl_yml

    return slides


def fill_report_params(reports, report_name, wb):

    info_ws = wb.sheet_by_name(return_sheet_name(report_name, '_Info'))
    client = info_ws.cell_value(9, 1)
    period = get_pretty_period(info_ws.cell_value(15, 1), info_ws.cell_value(15, 3))
    currency = get_pretty_currency(info_ws.cell_value(21, 1))

    rev_ws = wb.sheet_by_name(return_sheet_name(report_name, '_Review'))
    review = {}
    for r_num in range(1, rev_ws.nrows):
        title, text_1, range_ = rev_ws.row_values(r_num)

        ws_name = range_.split('!')[0].replace('\'', '')
        loc_ws_name = return_sheet_name(report_name, ws_name, local=True)
        if not review.get(loc_ws_name):
            review[loc_ws_name] = {
                'ws_name': ws_name,
                'titles': [title],
                'text_1': [text_1]
            }
        else:
            review[loc_ws_name]['titles'] += [title]
            review[loc_ws_name]['text_1'] += [text_1]

    for k, v in review.iteritems():
        v['title'] = u', '.join(set(v['titles']))
        if len(v['text_1']) > 1:
            v['text_1'] = [u'{}. {}'.format(i, text) for i, text in enumerate(v['text_1'], 1)]

    reports[report_name]['params'] = {
        'client': client, 'period': period, 'currency': currency,
        'report_name':
            u'Отчёт по поисковым запросам' if report_name == 'search_queries'
            else u'Отчёт по текстово-графическим объявлениям'
    }
    reports[report_name]['review'] = review

    return reports


def get_report_slides(reports, report_name, wb):
    with open(join(dirname(__file__), 'pptx_config.yml')) as fd:
        pptx_yml = yaml.load(fd)

    problem_sheets = reports[report_name]['review'].keys()
    report_slides = []
    for sl_key in pptx_yml['presentation'][report_name]:
        sl_yml = deepcopy(pptx_yml[report_name][sl_key])
        sl_yml['sl_key'] = sl_key

        f = False
        ws_names = sl_yml.get('ws_name')
        if isinstance(ws_names, list):
            f = len(set(ws_names) & set(problem_sheets)) == len(ws_names)
        elif ws_names:
            if ws_names in problem_sheets:
                ws_names = [ws_names]
                f = True

        if ws_names and f:
            for ws_name in ws_names:
                sl_yml = parse_problem(reports, report_name, sl_yml, ws_name, wb)
            if isinstance(sl_yml['text_holders']['text_1'], list):
                sl_yml['text_holders']['text_1'] = u'\n'.join(sl_yml['text_holders']['text_1'])

            report_slides.append(format_sl_yml(sl_yml, **reports[report_name]['params']))

        elif sl_key == 'spacer':
            pass

    if 'sitelinks' in [sl_yml_['sl_key'] for sl_yml_ in report_slides]:
        report_slides = list(filter(
            lambda sl_yml__: sl_yml__['sl_key'] not in ['sitelinks_search', 'sitelinks_networks'], report_slides))
    if 'callouts' in [sl_yml_['sl_key'] for sl_yml_ in report_slides]:
        report_slides = list(filter(
            lambda sl_yml__: sl_yml__['sl_key'] not in ['callouts_search', 'callouts_networks'], report_slides))
    if 'display_url' in [sl_yml_['sl_key'] for sl_yml_ in report_slides]:
        report_slides = list(filter(
            lambda sl_yml__: sl_yml__['sl_key'] not in ['display_url_search', 'display_url_networks'], report_slides))

    spacer_yml = deepcopy(pptx_yml[report_name]['spacer'])
    titles = get_report_titles(report_slides)
    if len(titles) < 6:
        spacer_yml['text_holders']['subtitle_1'] = titles
    else:
        idx = int(ceil(len(titles) / 2.))
        spacer_yml['text_holders']['subtitle_1'] = titles[:idx]
        spacer_yml['text_holders']['subtitle_2'] = titles[idx:]

    report_slides.insert(0, format_sl_yml(spacer_yml, **reports[report_name]['params']))

    reports[report_name]['slides'] = report_slides

    return reports


def parse_problem(reports, report_name, sl_yml, ws_name, wb):
    problem = reports[report_name]['review'][ws_name]

    if not sl_yml['text_holders'].get('title'):
        sl_yml['text_holders']['title'] = problem['title']

    if len(problem['text_1']) == 1:
        if not sl_yml['text_holders'].get('text_1'):
            sl_yml['text_holders']['text_1'] = problem['text_1'][0]
        else:
            sl_yml['text_holders']['text_1'] += problem['text_1']

    else:
        if not sl_yml['text_holders'].get('text_1'):
            sl_yml['text_holders']['text_1'] = problem['text_1']
        else:
            sl_yml['text_holders']['text_1'] += problem['text_1']

    if sl_yml.get('charts'):
        for ch_yml in sl_yml['charts']:
            if ch_yml.get('ws_name'):
                ws = wb.sheet_by_name(return_sheet_name(report_name, ch_yml['ws_name']))
            else:
                ws = wb.sheet_by_name(return_sheet_name(report_name, ws_name))
            ch_yml['data'] = read_chart_data(ws, ch_yml['chart_type'], ch_yml['data'])

            if ch_yml['chart_type'] == 'nested_clicks':
                label = u'{:+,.0f}\n({:+,.0%})'.format(
                    float(ws.cell_value(14, 11)), float(ws.cell_value(15, 11))
                ).replace(',', ' ')
                ch_yml['data']['series'][1]['label'] = label

    if sl_yml['layout'] == 'table':
        ws = wb.sheet_by_name(return_sheet_name(report_name, ws_name))
        rows = []
        for r_num in range(1, ws.nrows):
            rows.append(ws.row_values(r_num))

        sl_yml['table_data'] = rows

    return sl_yml


def format_sl_yml(sl_yml, **kwargs):
    for k, v in sl_yml.get('text_holders', {}).iteritems():
        if isinstance(v, list):
            sl_yml['text_holders'][k] = [unicode(vv).format(**kwargs) for vv in v]
        else:
            try:
                sl_yml['text_holders'][k] = unicode(v).format(**kwargs)
            except:
                pass

    return sl_yml


def get_report_titles(sl_ymls):
    titles = []

    for sl_yml in sl_ymls:
        title = sl_yml['text_holders']['title']
        if title not in titles:
            titles.append(title)

    return titles


def read_chart_data(ws, ch_type, data):

    if data.get('by_columns'):
        if 'series_col' in data.keys():
            data['series'] = []
            series = ws.col_values(data['series_col'], start_rowx=data['row'])
            for s_name in series:
                data['series'].append({'name': unicode(int(s_name))})

        for s_num, series in enumerate(data['series']):
            series['values'] = []
            for col_num in data['columns']:
                series['values'] += [get_chart_value(ws.cell_value(data['row'] + s_num, col_num))]

    elif data.get('by_rows'):
        for s_num, series in enumerate(data['series']):
            series['values'], series['labels'] = [], []

            if not data.get('categories'):
                data['categories'] = ws.col_values(data['categories_col'], start_rowx=data['row'])

            for r_num in range(len(data['categories'])):
                if ch_type == 'nested_clicks':
                    r_num = s_num

                try:
                    series['values'] += [get_chart_value(
                        ws.cell_value(data['row'] + r_num, data['columns'][s_num])
                    )]
                except IndexError:
                    series['values'] += [0.]

                if series.get('lab_column'):
                    series['labels'] += [get_chart_value(
                        ws.cell_value(data['row'] + r_num, series['lab_column'])
                    )]
    return data


def get_chart_value(cell_value):
    if cell_value == '':
        return 0
    else:
        return cell_value


def get_pretty_currency(currency):
    if currency == 'RUB':
        return u'руб.'
    elif currency == u'Не определена':
        return currency.lower()
    else:
        return currency


def get_pretty_period(date_1, date_2=None):
    if not date_2:
        return pretty_date(date_1, True)
    else:
        date_1, date_2 = pretty_date(date_1), pretty_date(date_2)
        if date_1 == date_2:
            return u'Период: {}'.format(date_1)
        else:
            return u'{} – {}'.format(date_1, date_2)


def pretty_date(date, long_=False):
    if not isinstance(date, datetime):
        date = datetime.strptime(date, '%Y-%m-%d')
    day, month, year = date.day, date.month, date.year

    if long_:
        months = {
            1: u'Января',
            2: u'Февраля',
            3: u'Марта',
            4: u'Апреля',
            5: u'Мая',
            6: u'Июня',
            7: u'Июля',
            8: u'Августа',
            9: u'Сентября',
            10: u'Октября',
            11: u'Ноября',
            12: u'Декабря',
        }
        return u'{} {} {}'.format(day, months[month].lower(), year)

    else:
        months = {
            1: u'Январь',
            2: u'Февраль',
            3: u'Март',
            4: u'Апрель',
            5: u'Май',
            6: u'Июнь',
            7: u'Июль',
            8: u'Август',
            9: u'Сентябрь',
            10: u'Октябрь',
            11: u'Ноябрь',
            12: u'Декабрь',
        }
        return u'{} {}\'{}'.format(day, months[month][:3].lower(), year)
