# -*- coding: utf-8 -*-
from typing import List, Any, Tuple

import constants
import printer_wrapper

from datetime import datetime, timedelta
from multiprocessing import Lock
from msgbus import MBEasyContext
from old_helper import read_swconfig
from helper import remove_accents

lock = Lock()
cache_header = ""
last_cache_time_larger_paper = None
last_cache_time_small_paper = None


class ClicheHelper(object):
    def __init__(self, mb_context, cnpj_contribuinte, insc_estadual):
        # type: (MBEasyContext, str, str) -> None
        self.mb_context = mb_context
        self.cnpj_contribuinte = cnpj_contribuinte
        self.insc_estadual = insc_estadual
        self.cliche = None

    def get_cliche(self):
        if self.cliche is None:
            razao_social = read_swconfig(self.mb_context, "Store.RazaoSocial")
            end_logradouro = read_swconfig(self.mb_context, "Store.EndLogradouro")
            end_numero = read_swconfig(self.mb_context, "Store.EndNumero").strip() or "S/N"
            end_compl = (read_swconfig(self.mb_context, "Store.EndCompl") or "").strip()
            bairro = read_swconfig(self.mb_context, "Store.Bairro")
            municipio = read_swconfig(self.mb_context, "Store.Municipio")
            cep = read_swconfig(self.mb_context, "Store.CEP")
            uf = read_swconfig(self.mb_context, "Store.UF")
            cnpj_contribuinte = self.cnpj_contribuinte
            inscr_estadual = self.insc_estadual
            formatted_ie = "IE: %s" % inscr_estadual
            self.cliche = [
                razao_social,
                "%s, %s %s %s" % (end_logradouro, end_numero, end_compl, bairro),
                "%s, %s %s-%s" % (municipio, uf, cep[:5], cep[5:]),
                "CNPJ: %s.%s.%s/%s-%s %s" % (cnpj_contribuinte[:2],
                                             cnpj_contribuinte[2:5],
                                             cnpj_contribuinte[5:8],
                                             cnpj_contribuinte[8:12],
                                             cnpj_contribuinte[12:],
                                             formatted_ie)
            ]
        return self.cliche

    def get_header_coupon(self, is_larger_paper=True):
        global cache_header

        last_cache_time = self.get_last_cache_time(is_larger_paper)
        seconds_to_renew = self.get_seconds_to_renew_cache((60 * 60) * 8)
        if self.reached_seconds_to_renew_cache(last_cache_time, seconds_to_renew):
            with lock:
                self.set_last_cache_time(is_larger_paper)
                cache_header = ""
                cache_header += constants.TXT_ALIGN_LT
                logo = printer_wrapper.get_logo(is_larger_paper)
                lines = self.get_cliche()

                if logo is None:
                    cache_header = constants.TXT_ALIGN_CT
                    for line in lines:
                        cache_header += remove_accents(line) + "\n"
                    return cache_header

                if not is_larger_paper:
                    cache_header = constants.TXT_ALIGN_CT
                    cache_header += logo
                    cache_header += constants.TXT_ALIGN_CT
                    for line in lines:
                        cache_header += remove_accents(line) + "\n"
                    return cache_header

                lines = self._adjust_size_lines_address(lines)
                logo = logo.split("\n")
                for line_logo, line_address in self._zip(logo, lines):
                    cache_header += "%s %s\n" % (line_logo.ljust(13, " "), remove_accents(line_address))

        return cache_header

    def _adjust_size_lines_address(self, lines):
        # type: (List[str, Any]) -> List[str]

        new_lines = []
        line_max_size = 44

        for line in lines:
            if len(line) < line_max_size:
                new_lines.append(line)
                continue

            new_lines += self.manager_lines_size(line, line_max_size)

        return new_lines

    def _zip(self, list_one, list_two):
        # type: (List[str], List[str]) -> List[Tuple]

        max_size = len(list_one) if len(list_one) > len(list_two) else len(list_two)
        columns = []
        for index in range(max_size):
            columns.append((self._get_column(index, list_one), self._get_column(index, list_two)))

        return columns

    @staticmethod
    def _get_column(index, list_data):
        # type: (int, List[str]) -> str

        try:
            return list_data[index]
        except IndexError:
            return ""


    @staticmethod
    def manager_lines_size(line, max_size=35):
        # type: (str, int) -> list

        lines = []
        while line != '':
            current_line = line[0:max_size]
            lines.append(current_line)
            line = line[len(current_line):]

        return lines

    @staticmethod
    def get_last_cache_time(is_larger_paper):
        global last_cache_time_larger_paper
        global last_cache_time_small_paper

        return last_cache_time_larger_paper if is_larger_paper else last_cache_time_small_paper

    @staticmethod
    def set_last_cache_time(is_larger_paper):
        global last_cache_time_larger_paper
        global last_cache_time_small_paper
        if is_larger_paper:
            last_cache_time_larger_paper = datetime.now()
            return

        last_cache_time_small_paper = datetime.now()

    @staticmethod
    def get_seconds_to_renew_cache(seconds_to_renew_cache):
        seconds_to_renew = 60 * 5
        try:
            seconds_to_renew = int(seconds_to_renew_cache)
        except TypeError as _:
            pass
        return seconds_to_renew

    @staticmethod
    def reached_seconds_to_renew_cache(last_cache, seconds_to_renew_cache):
        return not last_cache or datetime.now() > last_cache + timedelta(seconds=seconds_to_renew_cache)
