# -*- coding: utf-8 -*-
from itertools import product
from pptx.enum.text import MSO_ANCHOR, PP_ALIGN
from pptx.util import Cm, Pt
from presentation import COLORS, GIDES
from slides import get_placeholder_by_name


def insert_tables(slide, table_config, **kwargs):
    if table_config['type'] == 'shares':
        slide = insert_shares_table(kwargs.get('report'), slide, table_config)

    elif 'networks' in table_config['type']:
        slide = insert_networks_table(kwargs.get('task'), slide, table_config)

    return slide


def insert_shares_table(report, slide, table_config):
    cells = table_config['data']['cells']
    if not(isinstance(cells, list)):
        cells = [cells, ]

    for t_num, (sheet_name, table_cells) in enumerate(product(table_config['data']['sheet_name'], cells), 1):
        data = []
        for cell_address in table_cells.split(','):
            data.append([report[sheet_name][cell_address.strip()].text])

        table_frame = get_placeholder_by_name(slide, 'table_%i' % t_num).insert_table(len(data), 1)
        apply_table_params(table_frame, table_config['table_params'])

        for row_idx, data_row in enumerate(data):
            for col_idx, cell_data in enumerate(data_row):
                cell = table_frame.table.cell(row_idx, col_idx)
                cell.text = cell_data

                remove_borders(cell)
                if row_idx != len(data) - 1:
                    create_border(cell, 'bottom', Pt(1), COLORS['dark_grey'])

                base_cell_format(cell)

    return slide


def insert_networks_table(task, slide, table_config):
    header = table_config['header']
    rows_cnt = 11 if task.version == u'клиент+конкуренты' else 10
    start_row = 1 if task.version == u'клиент+конкуренты' else 0

    table_frame = get_placeholder_by_name(slide, 'table_1').insert_table(rows_cnt, len(header))
    apply_table_params(table_frame, table_config['table_params'])
    table = table_frame.table

    for col_idx, title in enumerate(table_config['header']):
        cell = table.cell(start_row, col_idx)
        cell.text = title

    for col_idx, col_name in enumerate(table_config['columns_order']):
        for row_idx, value in enumerate(task.networks_table[col_name].values, start_row + 1):
            cell = table.cell(row_idx, col_idx)
            cell.text = format_cell_value(col_name, value)

    if task.version != u'клиент+конкуренты':
        format_shares_table(table)
    else:
        format_bench_table(table_config['type'], table, task.client)

    return slide


def format_shares_table(table):
    share_cols = [2, 4, 6]
    banner_rows = {1: {'fore_color': COLORS['red'], 'font_color': COLORS['white']},
                   4: {'fore_color': COLORS['yellow']},
                   7: {'fore_color': COLORS['blue'], 'font_color': COLORS['white']}
                   }

    for row_idx, row in enumerate(table.rows):
        for col_idx, cell in enumerate(row.cells):
            if row_idx in [1, 4, 7] and col_idx in [7, 8, 9]:
                cell.text = u''

            kwargs = {
                'font_size': 20,
                'margins': {'left': 0.5, 'right': 0.5}
            }
            if row_idx == 0:
                kwargs.update({
                    'bold': True,
                    'font_name': GIDES['header_font_name'],
                    'border_width': Pt(3), 'border_color': COLORS['black']
                })
            else:
                kwargs.update(banner_rows.get(row_idx, {}))
            if col_idx in share_cols and not kwargs.get('fore_color'):
                kwargs['fore_color'] = COLORS['pale_grey']

            if row_idx + 1 == len(table.rows):
                kwargs['bottom_border'] = False

            format_cell(table, row_idx, col_idx, **kwargs)

    return table


def format_bench_table(table_type, table, client):

    if table_type == 'networks_key_metrics':
        share_cols = [2, 4, 6, 8, 10, 12]
        comp_cols, client_cols = [1, 3, 5], [7, 9, 11]
    else:
        share_cols = []
        comp_cols, client_cols = [1, 2, 3], [4, 5, 6]

    for row_idx, row in enumerate(table.rows):
        for col_idx, cell in enumerate(row.cells):
            kwargs = {
                'font_size': 20,
                'margins': {'left': 0.5, 'right': 0.5}
            }
            if row_idx in [0, 1]:
                kwargs.update({
                    'font_name': GIDES['header_font_name'],
                    'border_width': Pt(1), 'border_color': COLORS['black']
                })
                if row_idx == 0:
                    kwargs['alignment'] = PP_ALIGN.CENTER
                    if (table_type == 'networks_key_metrics' and 1 <= col_idx <= 6) or col_idx in comp_cols:
                        kwargs['fore_color'] = COLORS['yellow']
                    elif col_idx != 0:
                        kwargs['fore_color'] = COLORS['red']
                        kwargs['font_color'] = COLORS['white']
                elif row_idx == 1:
                    kwargs['bold'] = True

                if row_idx == 1 and col_idx in share_cols:
                    kwargs['fore_color'] = COLORS['pale_grey']

            elif row_idx in [2, 5, 8]:
                if table_type != 'networks_key_metrics' and col_idx != 0:
                    cell.text = u''

                if col_idx in comp_cols:
                    kwargs['fore_color'] = COLORS['dark_grey']

                elif col_idx in client_cols:
                    kwargs['fore_color'] = COLORS['dark_grey']

                elif col_idx in [0] + share_cols:
                    kwargs['fore_color'] = COLORS['dark_grey']

            else:
                if col_idx in share_cols:
                    kwargs['fore_color'] = COLORS['pale_grey']

            if row_idx + 1 == len(table.rows):
                kwargs['bottom_border'] = False

            format_cell(table, row_idx, col_idx, **kwargs)
            if row_idx == 1:
                create_border(table.cell(row_idx, col_idx), 'top', Pt(1), COLORS['black'])
                create_border(table.cell(row_idx, col_idx), 'bottom', Pt(3), COLORS['black'])
            if (table_type == 'networks_key_metrics' and col_idx == 6) or \
                    (table_type == 'networks_efficiency' and col_idx == 3):
                create_border(table.cell(row_idx, col_idx), 'right', Pt(1), COLORS['black'])

    merge_header_cells(table_type, table, client)

    return table


def merge_header_cells(table_type, table, client):
    if table_type == 'networks_key_metrics':
        cols = [[1, 6], [7, 12]]
    else:
        cols = [[1, 3], [4, 6]]

    for col_idx_1, col_idx_2 in cols:
        table.cell(0, col_idx_1).text = u'Среднее по группе конкурентов' if col_idx_1 == 1 else client
        if col_idx_1 == 1:
            create_border(table.cell(0, col_idx_1), 'right', Pt(1), COLORS['black'])
        merge_cells(table, col_idx_1, col_idx_2, 0)

    return table


def format_cell_value(cell_type, value):
    if cell_type == 'table_name':
        return value
    else:
        if 'share' in cell_type:
            return value.replace('.', ',')
        elif 'CR' in cell_type:
            format_ = u'{:.1%}'
        elif 'CPC' in cell_type:
            format_ = u'{:,.1f}'
        else:
            format_ = u'{:,.0f}'

        return format_.format(float(value)).replace(',', ' ').replace('.', ',')


def format_cell(table, row_idx, col_idx, **kwargs):
    cell = table.cell(row_idx, col_idx)
    remove_borders(cell)

    cell.fill.solid()
    cell.fill.fore_color.rgb = kwargs.get('fore_color', COLORS['white'])

    set_margins(cell, kwargs.get('margins'))
    cell.vertical_anchor = MSO_ANCHOR.MIDDLE

    p = cell.text_frame.paragraphs[0]
    if col_idx == 0:
        p.alignment = PP_ALIGN.LEFT
    else:
        p.alignment = kwargs.get('alignment', PP_ALIGN.RIGHT)

    font_format(p.font,
                font_name=kwargs.get('font_name', GIDES['font_name']),
                font_size=kwargs.get('font_size', 24),
                color=kwargs.get('font_color', COLORS['black']),
                bold=kwargs.get('bold', False)
                )

    if kwargs.get('bottom_border', True):
        create_border(cell,
                      position='bottom',
                      width=kwargs.get('border_width', Pt(1)),
                      color=kwargs.get('border_color', COLORS['black'])
                      )

    return cell


def set_margins(cell, margins=None):
    if margins:
        cell.margin_left = Cm(margins.get('left'))
        cell.margin_right = Cm(margins.get('right'))
    else:
        cell.margin_left = Cm(0)
        cell.margin_right = Cm(0)

    cell.margin_top = Cm(0)
    cell.margin_bottom = Cm(0)

    return cell


def base_cell_format(cell):
    cell.fill.solid()
    cell.fill.fore_color.rgb = COLORS['white']
    cell.vertical_anchor = MSO_ANCHOR.MIDDLE

    p = cell.text_frame.paragraphs[0]
    p.alignment = PP_ALIGN.RIGHT
    font_format(p.font)

    set_margins(cell)

    return cell


def font_format(font, font_name=GIDES['font_name'], font_size=24, color=COLORS['black'], bold=False):
    font.bold = bold

    font.name = font_name
    font.size = Pt(font_size)
    font.color.rgb = color

    return font


def apply_table_params(table_frame, params):
    table = table_frame.table
    for param in ['left', 'top']:
        if params.get(param):
            setattr(table_frame, param, Cm(float(params[param])))

    width = [params['column_width']] * len(table.columns) if not isinstance(params['column_width'], list) \
        else params['column_width']
    for col, w in zip(table.columns, width):
        col.width = Cm(float(w))

    height = [params['row_height']] * len(table.rows) if not isinstance(params['row_height'], list) \
        else params['row_height']
    for row_idx, (row, h) in enumerate(zip(table.rows, height)):
        if (row_idx == 0 and params.get('header_height')) or (row_idx == 1 and params.get('second_row')):
            table.rows[row_idx].height = Cm(float(params['header_height']))
        else:
            row.height = Cm(float(h))

    return table_frame


def merge_cells(table, col_idx_1, col_idx_2, row_idx):
    row_cells = [cell for cell in table.rows[row_idx].cells][col_idx_1:col_idx_2]
    row_cells[0]._tc.set('gridSpan', str(col_idx_2 - col_idx_1 + 1))

    return table


def create_border(cell, position, width, color):
    border = border_line(cell, position)

    border.w = width
    border.get_or_change_to_solidFill().get_or_change_to_srgbClr().val = str(color)

    return border


def remove_borders(cell):
    for position in ['left', 'right', 'top', 'bottom']:
        border = border_line(cell, position)
        border.get_or_change_to_noFill()

    return cell


def border_line(cell, position):
    if position == 'left':
        return cell._tc.tcPr.get_or_add_lnL()

    elif position == 'right':
        return cell._tc.tcPr.get_or_add_lnR()

    elif position == 'top':
        return cell._tc.tcPr.get_or_add_lnT()

    elif position == 'bottom':
        return cell._tc.tcPr.get_or_add_lnB()

    else:
        return None
