import requests, re, json
# from custom_exception.documentation import *
from bs4 import BeautifulSoup
from bs4.element import Tag



class UpdateApi():
    def __init__(self, ports: list[str]):
        self._type_operations: list[dict] = []
        self._dict_actions: dict[dict[dict]] = {}
        self._ports = ports
        self._home_page_text: str
        self._port: str = "5001"
        self._auth_actions: list[str] = []
        
        
    def _get_html(self, port: str, action: str|None = None) -> tuple[bool, str]:
        if type(action) == str:
            url = f"http://credreal.imobiliar.com.br:{port}/webservice/Imobiliar2/{action}"
        else:
            url = f"http://credreal.imobiliar.com.br:{port}/webservice/Imobiliar2"
            
        response = requests.get(url)
        if not response.ok:
            return True, f"Problema ao acessar documentação da Porta {port}" + f" e Action: {action}" if action else ""
        self.port = port
        return False, response.text
    

    def get_actions(self):
        for i, port in enumerate(self._ports):
            error, message = self._get_html(port)
            if error:
                if i == len(self._ports) - 1:
                    # raise DocumentationNotFoundError(message)
                    raise Exception(message)
                continue
            break
        self._home_page_text = message
        action_pattern = re.compile(r'href="javascript:void\(0\)"\s+rel="([^"]+)"')
        auth_actions = action_pattern.findall(self._home_page_text)[1:3]
        for action in auth_actions:
            temp = {
                "operator": "AUTH",
                "action": action
            }
            self._type_operations.append(temp)
        soup = BeautifulSoup(self._home_page_text)
        operators: list[Tag]= soup.select(".accordin")
        for operator in operators:
            
            operator_str = str(operator)
            actions = action_pattern.findall( operator_str)
            for action in actions:
                temp = {
                    "operator": operator,
                    "action": action
                }
                self._type_operations.append(temp)
                
                
        
    
    def search_actions(self):
        re_pattern = re.compile(r'{"Header".*?}}', re.DOTALL)
        for type_operation in self._type_operations:
            operator = type_operation["operator"]
            action = type_operation["action"]
            error, message = self._get_html(self.port, action)
            if error:
                # raise ActionNotFoundError(message)
                raise Exception(message)
            
            soup = BeautifulSoup(message, "html.parser")
            elements: list[Tag] = soup.select(".hljs-meta")
            if len(elements) > 3:
                # raise BodyExtractionError(f"Não foi possível extrair o body da action: {action}")
                raise Exception(f"Não foi possível extrair o body da action: {action}")
            request: Tag = elements[2]
            str_payload: str = request.get_text(strip=True)
            higienezed_payload: str = re_pattern.sub(" ", str_payload)
            payload = json.loads(higienezed_payload)
            header = payload["Header"]
            body = payload["Body"]
            for k, v in body:
                field_type = body[k]
                converted_type = None
                match field_type:
                    case "number":
                        converted_type = int
                    case "string":
                        converted_type = str
                    case "date":
                        converted_type = str
                    case _ if "," in field_type:
                        converted_type = float
                    case _:
                        message = f"Na action {action} não foi possivel idenficar o parametro {k} o tipo encontrado foi de {v}"
                        # raise InvalidDataTypeConverterError(message)
                        raise Exception(message)
                body[k] = converted_type
            new_action = {
                
                "Header": header,
                "Body": body
            }    
            self._dict_actions[operator][action] = new_action
    

                 
    def to_dict(self):
        return self._dict_actions
    
    def save_actions(self):
        with open("actions.json", "w", encoding="utf-8") as file:
            json.dump(self._dict_actions, file, indent=4, ensure_ascii=False)
    

teste = UpdateApi(ports=["5001"])
teste.get_actions()
teste.search_actions()
teste.save_actions()