# -*- coding: utf-8 -*-
import base64

from requests import exceptions
from nfcecanceler import NfceCancelerResponseParser, NfceCancelerRequestBuilder, NfceCancelerResponse
from nfcebuilder.nfceutil import NfceRequest
import logging
import os

from typing import Dict

logger = logging.getLogger("FiscalWrapper")


class NfceCanceler(object):
    def __init__(self, nfce_canceler_request_builder, nfce_canceler_response_parser, nfce_request, url_cancelamento, dir_enviados, versao_ws):
        # type: (NfceCancelerRequestBuilder, NfceCancelerResponseParser, NfceRequest, str, str, int) -> None
        self.nfce_canceler_request_builder = nfce_canceler_request_builder
        self.nfce_canceler_response_parser = nfce_canceler_response_parser
        self.dir_enviados = dir_enviados
        self.nfce_request = nfce_request
        self.url_cancelamento = url_cancelamento
        self.versao_ws = versao_ws
        if versao_ws in (1, 3):
            self.soap_act = "http://www.portalfiscal.inf.br/nfe/wsdl/RecepcaoEvento/nfeRecepcaoEvento"
        else:
            self.soap_act = "http://www.portalfiscal.inf.br/nfe/wsdl/NFeRecepcaoEvento4/nfeRecepcaoEvento"

    def cancel_order(
        self,
        order_response,     # type: str
        justification,      # type: str
        order_id,           # type: str
    ):
        # type: (...) -> Dict

        cancel_request_xml = self.nfce_canceler_request_builder.build_request(order_response, justification, self.versao_ws)

        try:
            response = self.nfce_request.envia_nfce(cancel_request_xml, self.url_cancelamento, soap_action=self.soap_act)
        except exceptions.RequestException:
            return {'status': False, 'message': "Problemas de Conexao", 'xml_response': None}
        except Exception as other_e:
            return {'status': False, 'message':  str(other_e), 'xml_response': None}
        else:
            nfce_canceler_response = self.nfce_canceler_response_parser.parse_response(response.text, self.versao_ws)
            if nfce_canceler_response.c_stat not in (NfceCancelerResponse.Canceled, NfceCancelerResponse.AlreadyCanceled):
                message = 'Invalid cStat {0}'.format(nfce_canceler_response.c_stat)
                return {'status': False, 'message':  message, 'xml_response': None}
            else:
                if nfce_canceler_response.c_stat == NfceCancelerResponse.Canceled:
                    idx_start = cancel_request_xml.find("<chNFe>") + 7
                    idx_final = cancel_request_xml.find("</chNFe>")
                    chave = cancel_request_xml[idx_start:idx_final]
                    serie_nota = chave[22:25]
                    numero_nota = chave[25:34].zfill(9)
                    idx_start = cancel_request_xml.find("<dhEvento>") + 10
                    idx_final = cancel_request_xml.find("</dhEvento>")
                    data_emissao = cancel_request_xml[idx_start:idx_final]
                    dir_arquivo = os.path.join(data_emissao[0:4], data_emissao[5:7], data_emissao[8:10])
                    name_template = "{}_{}_{}_nfe_cancelamento_NFe{}.xml"
                    file_name = name_template.format(serie_nota, numero_nota, order_id.zfill(9), chave)
                    file_path = os.path.join(self.dir_enviados, "Enviados", dir_arquivo, file_name)
                    with open(file_path, "w+") as nfe_cancel_file:
                        nfe_cancel_file.write(response.text)

                    xml_response = base64.b64encode(response.text)
                    return {'status': True, 'message': "Venda cancelada com sucesso", 'xml_response': xml_response}
                elif nfce_canceler_response.c_stat == NfceCancelerResponse.AlreadyCanceled:
                    return {'status': True, 'message': "Venda já cancelada anteriormente", 'xml_response': None}
                else:
                    return {'status': False, 'message': "Erro ao tentar cancelar venda", 'xml_response': None}
