# encoding: utf-8
import locale

from typing import (
    Any,
    List,
    Optional,
    Union,
)

import constants
from basereport import (
    TableReport,
    ReportColumnDefinition,
)
from report import Part
from helper import remove_accents

COLS = 38
SINGLE_SEPARATOR = ("-" * COLS)
SEPARATOR = ("=" * COLS)
DESCR = 17
DATE_TIME_FMT = "%d/%m/%Y %H:%M:%S"


def center(s):
    s = _cut(s)
    miss = COLS - len(s)
    if miss == 0:
        return s
    left = miss / 2
    return (" " * left) + s + "\n"


def join(dic1, dic2):
    d = dict(dic1)
    d.update(dic2)
    return d


def single_line_separator():
    return SINGLE_SEPARATOR + "\n"


def double_line_separator():
    return SEPARATOR + "\n"


def empty_line():
    return " " * COLS + "\n"


def break_line():
    return "\n"


def add_amount_line(descr, qty=None, amount=None, info=None):
    if amount is not None:
        amount = format_number(float(amount))

    descr = descr[0:DESCR]
    if len(descr) < DESCR:
        descr += '.' * (DESCR - len(descr))

    if qty is not None:
        line = "%s: [%4s] " % (descr, qty)
    else:
        line = "%s: " % descr

    if amount is not None:
        if qty is None:
            line += "       "
        remain = COLS - len(line) - 3
        line += "R$ %*s" % (remain, amount)
    elif info is not None:
        remain = COLS - len(line)
        line += "%*.*s" % (remain, remain, info)

    line += "\n"

    return line


def add_table_line(columns, columns_height, align=None, format_type=None, character_to_add=None):
    index = 0
    lines = ""
    total_columns = len(columns)
    for column in columns:
        current_format_type = 'string' if format_type is None else format_type[index]
        current_align = 'left' if align is None else align[index]
        current_character_to_add = ' ' if character_to_add is None else character_to_add[index]
        current_final_character = ''
        if len(current_character_to_add) > 1:
            current_character_to_add = character_to_add[0][0]
            current_final_character = character_to_add[0][1]

        column = str(column)
        column_len = columns_height[index]

        if current_format_type == 'float':
            formatted_number = '%.2f' % float(column)
            remain = column_len - len(formatted_number)

            if current_align == 'left':
                line = '{0:<{1}s}'.format(formatted_number, remain)
            else:
                line = '{0:>{1}s}'.format(formatted_number, remain)
        elif current_format_type == 'integer':
            line = column[0:column_len]
        else:
            line = column[0:column_len]

        add_characters = column_len - len(remove_accents(line)) if column_len - len(remove_accents(line)) > 0 else 0

        if add_characters == 0:
            line = column[0:column_len - 1]
            if index != total_columns - 1:
                lines += line
                if current_final_character != '':
                    line_list = list(lines)
                    line_list[-1] = current_final_character
                    lines = "".join(line_list)

                lines += " "
            else:
                lines += line
        else:
            if current_align == 'right':
                if index != total_columns - 1:
                    lines += (current_character_to_add * (add_characters - 1)) + line + " "
                else:
                    lines += " " + (current_character_to_add * (add_characters - 1)) + line
            else:
                if index != total_columns - 1:
                    lines += line + (current_character_to_add * (add_characters - 1))

                    if current_final_character != '':
                        line_list = list(lines)
                        line_list[-1] = current_final_character
                        lines = "".join(line_list)

                    lines += " "
                else:
                    lines += line + (current_character_to_add * add_characters)

        index += 1

    return lines + "\n"


def add_key_value_line(key, value):
    line = key
    remain = COLS - len(line)
    line += value[0:remain] + "\n"

    if len(value) > remain:
        line += value[remain: (2 * COLS) - remain] + "\n"

    return line


def set_font(font_type):
    font_a = b'\x1b\x4d\x00'
    font_b = b'\x1b\x4d\x01'

    if font_type == 'B':
        return [Part(font_b, [])]

    return [Part(font_a, [])]


def bold_on():
    return [Part(b'\x1b\x45\x01', [])]


def bold_off():
    return [Part(b'\x1b\x45\x00', [])]


def cut_paper():
    return [Part(b'\x1dV\x01', [])]


def rollback_printer_default_font():
    report = "{}{}{}".format(constants.HW_INIT, constants.TXT_NORMAL, constants.TXT_BOLD_OFF)
    report += "{}{}".format(constants.TXT_FONT_A, constants.TXT_ALIGN_LT)

    return report


def _cut(s):
    return s[:COLS] if (len(s) > COLS) else s


def format_number(number, decimal_places=2, decimal_separator='.', thousand_separator=','):
    sign = '-' if number < 0 else ''
    number = abs(number)
    number, dec = ("%.*f" % (decimal_places, number)).split('.')

    if thousand_separator:
        sepPos = len(number) - 3
        while sepPos >= 1:
            number = number[:sepPos] + thousand_separator + number[sepPos:]
            sepPos -= 3

    if decimal_separator:
        number += (decimal_separator + dec)

    return sign + number


def format_line(
    title,              # type: Optional[str]
    text,               # type: Optional[str]
    columns,            # type: int
    definition,         # type: List[ReportColumnDefinition]
    encoding='ASCII',   # type: Optional[str]
):
    # type: (...) -> List

    if not text:
        return []

    lines = []
    current_string_start = 0
    current_string_end = definition[1].width if title else columns

    while len(text) > 0:
        if title and current_string_start == 0:
            lines.append(TableReport(
                lines=[[title, text[:current_string_end]]],
                column_definitions=definition,
                encoding=encoding,
            ))
        else:
            lines.append(TableReport(
                lines=[[text[current_string_start:current_string_end]]],
                column_definitions=definition,
                encoding=encoding,
            ))

        if current_string_end > len(text):
            break

        current_string_start = current_string_end
        current_string_end += columns

    return lines


def format_price(price):
    formatted_value = '{0:,.2f}'.format(price)
    return formatted_value


def str_float(
    float_num     # type: float
):
    # type: ('...') -> str
    return locale.format("%.2f", float_num, True)


def set_inline_text(
    parts,          # type: List
    title,          # type: str
    text,           # type: str
    columns,        # type: int
    definition,     # type: Any
):
    # type: (...) -> None

    value = remove_accents(
        text=text,
    )

    parts.extend(
        format_line(
            title=title,
            text=value,
            columns=columns,
            definition=definition,
        )
    )


def translate_pos_label(
    pos_id,    # type: Any[Union[str, int]]
):
    # type: (...) -> str

    from sysactions import get_model
    from helper import translate_pos_label

    pos_id = 0 if pos_id == "Todos" else pos_id
    model = get_model(posid=pos_id)
    return translate_pos_label(model=model)
