
# -- coding: utf-8 --
'''PYTHONIOENCODING=utf-8 python3 ws.py mercos'''

import  re, json
from datetime import datetime, timedelta
#generic = importlib.import_module('generic')
from   generic.gn_api       import   gn_api # 
from   generic.gn_request   import   Request # 
# from   generic.gn_mysql import gn_mysql # 

# apiKey   : MgDVLU610ibLzsUWk3RoXJJipMXeWT
# apiToken : MgDVLU610ipHSe9hzVaRLpWwJGPhmlj

# Link da documenta&ccedil;&atilde;o da API
# https://auvoapiv2.docs.apiary.io/#

# Link da API: https://api.auvo.com.br/v2

# FORMATO DE SAIDA
# taskID
#key|externalId|idUserFrom|userFromName|idUserTo|userToName|customerId|customerDescription|taskType|taskTypeDescription|creationDate|taskDate|latitude|longitude|address|orientation|priority|deliveredOnSmarthPhone|deliveredDate|finished|report|visualized|visualizedDate|checkIn|checkInDate|checkOut|checkOutDate|checkinType|keyWords|inputedKm|adoptedKm
#TAREFA|CODIGOEXTERNO|IDDOUSUARIO|NOMEDOUSUARIO|CODIGODOUSUARIOCRIARDOR|NOMEDOUSUARIOCRIADOR|CNPJCLIENTE|NOMECLIENTE|IDTAREFATIPO|DESCRICAOTAREFATIPO|DATACRIACAO|DATADATAREFA|LATITUDE|LONGITUDE|ENDERECO|ORIENTACOES|PRIORIDADES|REQUISICAOPORSMARTPHONE|DATAREQUISICAO|TERMINADO|RELATORIO|VISUALIZADO|DATADAVISUALIZACAO|HOUVECHECKIN|DATADOCHECKIN|HOUVECHECKOUT|DATADOCHECKOUT|TIPODECHECKIN|PALAVRASCHAVES|KMINFORMADO|KMUSADO

#TAREFAFILES|IMAGEM|TIPODOARQUIVO|SUBTITULO|EXTENSAODOARQUIVO|IDIMAGEM|DESCRICAO

#TAREFAQUESTIONARIOS|DESCRICAODOQUESTIONARIO|IDDOQUESTIONARIO|IDDAPERGUNTA|DESCPERGUNTA|IDRESPOSTA|DESCRESPOSTA|DATARESPOSTA|...REPETE QUANTAS VEZES EXISTIR RESPOSTAS PARA ESSA PERGUNTA DESSE QUESTIONARIO

# TAREFAEQUIPAMENTO|IDDOEQUIPAMENTO

class auvo(gn_api):
    
    def __init__(self, argv:list):
        self.db         = False
        self.suffix     =  '_api_os'
        
        setup = self.setup(argv)
        
        """  "auth" : HTTPProxyDigestAuth(
            'Robson.privitera@br.multivac.com', 'bb50WDWD'
        ) """
        """ "proxies" : {
            'https': 'https://Robson.privitera@br.multivac.com:bb50WDWD@login.microsoftonline.com/common/federation/oauth2'
        }
        , """  
        """  self.params = {
            "base_url" :'https://api.auvo.com.br/v2/'
        } 
        """
        
        token = self.auvo_token(setup)
        
        self.auvo_request = Request(
                base_url = "https://api.auvo.com.br/v2/"
            ,   headers  = {
                    "Authorization": "Bearer {}".format(token['result']['accessToken'])
                }
            
        )
        
        super(auvo, self, ).__init__()
        
    
    def auvo_token(self,setup):
        ## ApplicationToken  = setup[0]    [  'NMTOKEN1API'] 
        ## CompanyToken      = setup[0]    ['NMTOKEN1DADOS']
        
        req =  Request().doRequest(
                base_url = "https://api.auvo.com.br/v2/"
            ,   rote     = "login"
            ,   params   = {
                #    "apiKey"   : ApplicationToken
                #,   "apiToken" : CompanyToken
                **self.get_token('apiKey'),
                **self.get_token('apiToken')
            })
        
        if req.status_code == 200 :    
            return req.json()
        else :
            exit("erro ao tentar recuperar token")
            
        
    """
    .########.####.##.......########.########...#######.....########.....###.......########...#######..########....###...
    .##........##..##..........##....##.....##.##.....##....##.....##...##.##......##.....##.##.....##....##......##.##..
    .##........##..##..........##....##.....##.##.....##....##.....##..##...##.....##.....##.##.....##....##.....##...##.
    .######....##..##..........##....########..##.....##....##.....##.##.....##....########..##.....##....##....##.....##
    .##........##..##..........##....##...##...##.....##....##.....##.#########....##...##...##.....##....##....#########
    .##........##..##..........##....##....##..##.....##....##.....##.##.....##....##....##..##.....##....##....##.....##
    .##.......####.########....##....##.....##..#######.....########..##.....##....##.....##..#######.....##....##.....##
    """
    def rote_filter_tasks(self) :
        
        endDate     = datetime.now()
        startDate   = endDate - timedelta(days=90)
        # cria um intervalo de tempo entre o dia de Hoje e 90 dias atras
        paramFilter = """
            {{
                "status": 3
            ,   "startDate":"{startDate}"
            ,   "endDate":"{endDate}"
            
            }}
        
        """.format(
                startDate = startDate.strftime("%Y-%m-%d %H:%M:%S")
            ,   endDate = endDate.strftime("%Y-%m-%d %H:%M:%S")
        )
        
        
        queryParams = self.mountRouteParams(
            {
                    "page"          : 1
                ,   "pageSize"      : 100
                ,   "order"         : 1
                ,   "paramFilter"   : paramFilter.replace('\n','').replace("  ","")
            })
        
        return queryParams
        
        
    def afterGet_tasks(self, data):
        return data.get('result',{}).get('entityList',[])
        
    
    def pagination_rules(self, req, data):
        #'pedidos/?status=2&alterado_apos=2021-07-12 15:41:29'
        req_data    = self.tryJson(req)
        links       = req_data.get('result',{}).get('links',[])
        next_page,   = [link for link in links if link['rel'] == 'nextPage'] or [None]
        if next_page:
            params = next_page.get('href').split('?')
            return f"tasks/?{params[1]}"
            
        
        return None
        
        
    def tasks_handler(self, data) :
        import os
        self.tasks = data #['result']['entityList']
        tasks_values = []
        
        # Leitura de todas as tasks vinda da api
        append = False
        controller = 0
        #! TODO: ANALISAR ANTES DE ENVIAR
        #for task in filter(lambda task: task['taskID'] in [19996205], self.tasks):
        for task in self.tasks:
                
            self.taskMd5 = self.hashMd5(task)
            
            isRegisterd = self.exists("CDOSEXTERNO","TBRETORNOOS",[
                    "CDOSEXTERNO = '{}'".format(task['taskID'])
                ,   "HASHMD5 = '{}'".format(self.taskMd5)
            ])
            
            if (isRegisterd) :
                continue 
            else : controller += 1
            
            self.current_task = controller + 1, task
            flag = "w+" if controller == 0 else "a+"
            task_arr = self.handle_tasks_values(controller)
            
            text_cobol = "\n".join(task_arr) + "\n"
            
            # to avoid codec can't encode character u2013
            text_cobol = text_cobol.replace('–','-')
            # para evitar que caracteres nao aceitos sejam enviados
            text_cobol = text_cobol.encode('iso-8859-1','ignore')
            text_cobol = text_cobol.decode('iso-8859-1')
            self.write_file(text_cobol, self.saida_cobol ,flag= flag, encoding='iso-8859-1' )
            
            
        # Converto to utf8 to iso
        
    
    def handle_tasks_values(self, task_index) :
        data = []
        # Leitura de cada elemento  do map T, TF, TQ
        for map_dict in self.atualWs['task-map'] :
            data.append(self.handle_attr_dict(map_dict))
            
        return data
        
    def hashMd5(self, task) :
        import hashlib
        
        json_text = json.dumps(task)
        md5 = hashlib.md5(json_text.encode('utf-8'))
        return md5.hexdigest()
        #5f08fd5f115d7a4419f983ba512c566b
        
    
    def flatten_json(self,y):
        out = {}

        def flatten(x, name=''):
            if type(x) is dict:
                for a in x:
                    flatten(x[a], name + a + '_')
            elif type(x) is list:
                i = 0
                for a in x:
                    flatten(a, name + str(i) + '_')
                    i += 1
            else:
                out[name[:-1]] = x

        flatten(y)
        return out
        
    
    
    def handle_attr_dict(self, map_dict) :
        
        data_line = []
        task_increment_id   = "T" + str(self.current_task[0]).rjust(2,'0')
        #Percore as chaves da tarefa
        for i,item in enumerate(self.atualWs['task-map'][map_dict]) :
            #recupera os valores baseado no mapa
            data_line.append (self.handleField(item, self.current_task[1]))
            
        
        # Se o valor da linha for uma lista entao monta um sequencia nova
        if data_line and isinstance(data_line[0], list) :
            
            str_data_line = [ "{0}|{1}".format(
                    task_increment_id + map_dict + str(k+1)
                ,   line
            ) for k,line in enumerate(data_line[0]) ]
            
                
            return  "\n".join(str_data_line)
            
        else :
            str_data_line = "|".join(map(str, data_line))
            return "{0}|{1}" .format(task_increment_id, str_data_line)
        
        #self.write_file(data="\n".join(data_line), path="./saida_cobol.txt")
        
        
    """
    ..######..##.....##..######..########..#######..##.....##....########.########.....###....##....##..######..##..........###....########.########
    .##....##.##.....##.##....##....##....##.....##.###...###.......##....##.....##...##.##...###...##.##....##.##.........##.##......##....##......
    .##.......##.....##.##..........##....##.....##.####.####.......##....##.....##..##...##..####..##.##.......##........##...##.....##....##......
    .##.......##.....##..######.....##....##.....##.##.###.##.......##....########..##.....##.##.##.##..######..##.......##.....##....##....######..
    .##.......##.....##.......##....##....##.....##.##.....##.......##....##...##...#########.##..####.......##.##.......#########....##....##......
    .##....##.##.....##.##....##....##....##.....##.##.....##.......##....##....##..##.....##.##...###.##....##.##.......##.....##....##....##......
    ..######...#######...######.....##.....#######..##.....##.......##....##.....##.##.....##.##....##..######..########.##.....##....##....########
    """
    def get_task_md5(self, value):
        return self.taskMd5
        
    
    def  custom_userId(self, value):
        newValue =  value.split('-')[0].strip()
        return newValue
        
    
    def custom_customerId(self, id) :
        # Recuperar o cnpj do cliente para aplciacao 
        return self.custom_auvo_translate(id, 'customers','cpfCnpj')
        
        
    def custom_equipmentsId(self, id) :
        if id:
            req  = self.custom_auvo_translate(id[0], 'equipments')
            name = str(req.get('name')).replace(" ","").replace("-","|")
            identifier = str(req.get('identifier'))
            return [name+"|"+identifier]
        else:
            return ['']
    
    def custom_auvo_translate(self, id, path, attr = False) :
        json_ = {}
        req = self.api_request.doRequest(rote="{0}/{1}".format(path,id))
        if req.status_code == 200 :
            json_ = req.json()
            if attr:
                return json_['result'][attr]
            else :
                return json_['result']
        
        return id
        
        
    def remove_lines_breack(self, data) :
        return data.replace("\n", "@@")
        
    
    def custom_attachments(self, data) :
        values = ['']
        if isinstance(data, list) :
            values = ["|".join(map(str,item.values())) for item in data ]
            
        return values
        
    def removePreposicao(self, text, prepos) :
            
        text = ' '.join([k for k in text.split(" ") if k not in prepos])
        return text
    
    def custom_questionnaires(self, data) :
        from functools      import reduce

        values = []
        allowed = ['DESPESAS','DETALHAMENTO DAS HORAS']
        # Filtra apenas os que estao permitidos
        questionnaires = filter(lambda e: e['questionnaireDescription'] in allowed, data)
        for i, questionnaire in enumerate(questionnaires) :
            # Filtra apenas as perguntas que tem respostas
            answers = questionnaire['answers']
            questionnaireDescription = questionnaire['questionnaireDescription']
            
            template     = self.item_data['templates'][questionnaireDescription]
            group_size   = len(template)
            
            template_pos = 0
            
            questionnaire_group = []
            answers_groups      = []
            group_count = 1
            empty_count = 0
            
            
            while True :
                
                template_title = self.get_index(template, template_pos)
                if not template_title :
                    
                    answers_groups.append(questionnaire_group)
                    template_pos = 0
                    group_count += 1
                    #if not group_size:
                    #    group_size  = len(questionnaire_group)
                    questionnaire_group = []
                    continue
                else :
                    template_title  = template[template_pos].lower() #self.removePreposicao(template[template_pos].lower(),['de ','da ', 'do '])
                

                questionary_answer_list = [__answer for __answer in answers 
                        if template_title in self.removePreposicao(__answer['questionDescription'].lower(),['de','da', 'do'] )
                        and str(group_count) in __answer['questionDescription']
                ]
                
                questionary_answer = self.get_index(questionary_answer_list, 0)
                
                if questionary_answer :
                    empty_count = 0
                    questionnaire_group.append(questionary_answer)
                else: 
                    questionnaire_group.append({
                            'questionId':""
                        ,   'questionDescription':template_title
                        ,   'replyId':""
                        ,   'reply':""
                        ,   'replyDate':""
                    })
                    if group_size and empty_count >= group_size: 
                        break
                    empty_count += 1
                    
                    
                template_pos += 1
            
        
                
                
            # Retornara todos os grupos que tenha pelo menos uma resposta valida
            valid_groups = filter(lambda group: any([i['reply'] for i in group ]), answers_groups)
                
            for group in valid_groups :
                #Junta todos os dados de um grupo em uma unica linha
                rdc = reduce(lambda old, curr: old + "{}".format(
                    "|" if old else ""
                ) + "|".join(map(str,curr.values())),group, "")
                
                
                
                values.append("{0}|{1}|{2}|".format(
                        questionnaire['questionnaireDescription']
                    ,   questionnaire['questionnaireId']
                    ,   rdc
                ))
            
        if values :
            return values
        
        return ['']
        

import requests.auth
class HTTPProxyDigestAuth(requests.auth.HTTPDigestAuth):
    def handle_407(self, r):
        """Takes the given response and tries digest-auth, if needed."""

        num_407_calls = r.request.hooks['response'].count(self.handle_407)

        s_auth = r.headers.get('Proxy-authenticate', '')

        if 'digest' in s_auth.lower() and num_407_calls < 2:

            self.chal = requests.auth.parse_dict_header(s_auth.replace('Digest ', ''))

            # Consume content and release the original connection
            # to allow our new request to reuse the same one.
            r.content
            r.raw.release_conn()

            r.request.headers['Authorization'] = self.build_digest_header(r.request.method, r.request.url)
            r.request.send(anyway=True)
            _r = r.request.response
            _r.history.append(r)

            return _r

        return r

    def __call__(self, r):
        if self.last_nonce:
            r.headers['Proxy-Authorization'] = self.build_digest_header(r.method, r.url)
        r.register_hook('response', self.handle_407)
        return r
        
        
        
        
        
        
        
        
        
        
    