
from generic.gn_api  import gn_api 
from generic.gn_json import gn_json
from string import Formatter
import json


class simple_api(gn_api, gn_json):
    def __init__(self, argv:list):
        super(simple_api, self, ).__init__()
        #self.estr = {}
        
    
    def handle_send(self, data) :
        """ Metodo para manipular o envio """
        self.current_data = data
        self.prepare_send(data)
        
        # Faz um tratamento no dados antes de enviar
        func_rote = self.fixed_rote()
        func = f"beforeSend_{func_rote}"#.format(func_rote)
        # Tratamento de dados antes de enviar
        beforeSend = self.call(func, data, is_required= self.atualWs.get('need_beforeSend',False))
        
        response = self.send(data)
        
        
        self.current_data = {}
        return self.handle_response(response)
        
    
    def prepare_send(self, data) :
        """ Metodo que prepara os dados de envio """
        
        self.current_method = self.method.upper()
        
        self.current_rote = self.atualWs['rote']
        if '{' in self.current_rote and '}' in self.current_rote:
            fmt = NoneAsEmptyFormatter()
            self.current_rote = fmt.format(self.current_rote, **self.rote_data.get('path',{}))
            if (self.current_rote.endswith('/')):
                self.current_rote = self.current_rote[:-1]
        
    
    def send(self ,data) :
        #""" Envia dados para uma api - via POST ou PUT """
        
        if 'send' in self.atualWs and self.atualWs['send'] == False:
            return 
            
        raw_type = "json"
        
        # mudar em configuracoes o raw_type se for diferente - ver na documentacao de cada api
        if self.config['raw_type'] == "text" :
            data     =  json.dumps(data)
            raw_type =  "data"
        
        params = {
                "rote"    : self.current_rote
            ,   "method"  : self.current_method
            ,   raw_type  : data
        }
        print(f":params |> {params}")
        # ! SENDREQUEST
        return self.throttling( **params )
        
    
    def handle_response(self, response):
        
        reponse_data = self.tryJson(response)
        response_map = self.atualWs.get('response',{})
        response_template = response_map.get('template',{})
        data = self.generate_values(response_template, reponse_data)
        
        return self.handle_output(data)
        
    
    def handle_output(self, data):
        rote   = self.fixed_rote()
        return self.call(f"handle_output_{rote}", data)
        
    
        
    def generate_values(self, fields, data):
        values = dict()
        for field in fields:
            new_value = self.handleField(field, data)
            if isinstance(new_value, bool) and not new_value:
                new_value = 0
            values[field['to']] = new_value
            
        return values
        
    
    def handleField(self, item, data):
        
        value = False
        self.item_data = item
        
        
        if "from" in item :
            value = self.jsonValueByPath(item['from'], data)
        #if item['from'] in data :
            
            if item['from'] == 'root':
                value = data
            
        if "list" in item:
            field_list = item.get("list",{})
            if isinstance(value, dict) :
                return [self.generate_values(field_list, value)]
            elif isinstance(value, list) :
                return [self.generate_values(field_list, v) for v in value]
                
            
        if "fields" in item:
            field_child = item.get("fields",{})
            return self.generate_values(field_child, value)
            
        if "default" in item and not value:
            value = item['default']
        
        if "custom_translate" in item:
            #Se o campo tem um tratamento unico chama a funcao dele
            #value = getattr(self, item['custom_translate'])( value )
            value = self.call(item['custom_translate'], value, item)
        
        if "translate_by_item" in item :
            value = self.call(item['translate_by_item'], value, item)
            
        if "translate_by_branch" in item :
            currentValue =  value
            func_name = f"{item['translate_by_branch']}_{self.nmlkgrupo.lower()}"
            
            value = self.call(func_name, value, item)
            if value == None:
                value = currentValue
            
        if "translate" in item :
            value = self.translate(id=value, table=item['translate'], reverse=True)
            
        
        if 'translate_by_type' in item:
            value = self.translateByType(value, item['translate_by_type'])
            
            
        if 'globalThis' in item:
            globalThis = item['globalThis']
            attr = globalThis if isinstance(globalThis, str) else item['integration']
            setattr(self, attr.replace("/","_"), value )
            
        
        return value
        
    
    # definir sempre o files->entrada=caminho/do/arquivo
    def txt_to_dict(self):
        files           = self.rote_data.get('files')
        entrada         = files.get('entrada' )
        
        txt             = self.readFile(entrada)
        linhas_arquivo  = txt.split("\n")
        cabecalho       = linhas_arquivo[0]
        corpo           = linhas_arquivo[1:]
        
        estrutura = {}
        
        mapa_operacoes = {}
        
        
        propiedades_coluna = cabecalho.split(";")
        for propiedade in propiedades_coluna:
            estrutura_nome, estrutura_tipo, estrutura_tamanho, estrutura_variacao, estrutura_is_not_null = propiedade.split("|")
            if estrutura_nome == 'FGCUD':
                continue
                
            
            estrutura[estrutura_nome] = ({
                "tipo":estrutura_tipo,
                "tamanho":estrutura_tamanho,
                "variacao":estrutura_variacao,
                "not_nulo":estrutura_is_not_null == 'S',
            })
            
        
        def_ = ""
        for linha in corpo:
            
            linha_dados = linha.split(";")
            mapa_estrutura = {}
            for index, valor in enumerate(linha_dados):
                hed_ = propiedades_coluna[index]
                if(index == 0 ):
                    def_ = valor
                    if(def_ not in mapa_operacoes):
                        mapa_operacoes[def_] = []
                    continue
                    
                estrutura_nome = hed_.split("|")[0]
                
                estrutura_atual = estrutura[estrutura_nome]
                
                mapa_estrutura[estrutura_nome] = ({
                    **estrutura_atual,
                    "valor": self.__tratar_valor(valor, **estrutura_atual)
                })
                #linha_dados_json.append(mapa_estrutura)
            mapa_operacoes[def_].append(mapa_estrutura)
                
        return mapa_operacoes
        
    
    def __tratar_valor(self, valor, **kwargs):
        tipo        = kwargs.get('tipo')
        variacao    = kwargs.get('variacao')
        try:
            if len(valor) > 0 :
                if   "INT" in tipo  :
                    valor = int(valor) 
                elif "DOUBLE" in tipo :
                    valor = float(valor) 
                elif  "DECIMAL" in tipo  :
                    #valor = valor.replace(".","").replace(",",".")
                    valor = float(valor)
                elif "DATETIME" in tipo :
                    valor = "{0}-{1}-{2} {3}:{4}:{5}".format(valor[0:4],valor[4:6],valor[6:8],valor[8:10],valor[10:12],valor[12:14]) if int(valor) else None
                elif "DATE" in tipo :
                    valor = "{0}-{1}-{2}".format(valor[0:4],valor[4:6],valor[6:]) if int(valor) else None
                elif "I" in variacao :
                    valor = self.__img_encode64(valor)
                else :
                    valor = valor.strip()
                    valor = valor.replace("§","\n")
        except:
            valor = ""
            
        if not valor and tipo in  ['INT', 'DOUBLE', 'DATETIME', 'DATE'] :
            valor = None
        return valor
        
    
    def __img_encode64(self, value) :
        import base64
        import os.path
        filename, file_extension = os.path.splitext(value)
        sucesso, image = self.readFile(path=value, flag='rb', encoding=None)
        extension = file_extension.replace('.','')
        
        base64 = (base64.b64encode(image)).decode('utf8')
        
        return f"data:image/{extension};base64,{base64}"
        
    

class NoneAsEmptyFormatter(Formatter):
    def get_value(self, key, args, kwargs):
        v = super().get_value(key, args, kwargs)
        return '' if v is None else v