# =================================================================================================
# SERVIDOR DE API LOCAL PARA EXCEL
# =================================================================================================
#
# DESCRIÇÃO:
# Este script Python inicia um servidor web local na porta 5000. Ele atua como uma API 
# personalizada para buscar dados financeiros de fontes externas e fornecê-los de forma 
# formatada para uso em planilhas do Excel, principalmente através de funções VBA.
#
# FONTES DE DADOS:
# 1. Dados de Opções: Extraídos de https://opcoes.net.br/
# 2. Dados de Dividendos: Extraídos de https://statusinvest.com.br/
#
# DEPENDÊNCIAS:
# Este script requer as bibliotecas 'requests' e 'beautifulsoup4' para o scraping de dividendos.
# Instale-as com o seguinte comando no terminal:
# pip install requests beautifulsoup4
#
# COMO EXECUTAR:
# 1. Certifique-se de que as dependências acima estão instaladas.
# 2. Abra um terminal ou prompt de comando.
# 3. Navegue até a pasta onde este arquivo está salvo.
# 4. Execute o comando: python nome_do_arquivo.py
# 5. O servidor permanecerá em execução. Para pará-lo, pressione CTRL+C no terminal.
#
# -------------------------------------------------------------------------------------------------
# DOCUMENTAÇÃO DA API (COMO USAR NO EXCEL)
# -------------------------------------------------------------------------------------------------
#
# Endpoint Principal: http://localhost:5000/dados
#
# Parâmetros Obrigatórios:
#   - code: O ticker do ativo ou código da opção (ex: petr4, BOVAJ28).
#   - field: A informação desejada.
#
# --- FUNCIONALIDADES DISPONÍVEIS ---
#
# 1. DADOS DE OPÇÕES
#    - Objetivo: Obter Strike e/ou Vencimento de uma opção.
#    - Exemplo de uso no Excel (VBA): GetWebData("BOVAJ28", "strike-vencimento")
#
#    - Parâmetro 'field' para Strike: "strike"
#      - URL: http://localhost:5000/dados?code=BOVAJ28&field=strike
#      - Retorna: Uma string com o valor do strike (ex: "146,00").
#
#    - Parâmetro 'field' para Vencimento: "vencimento"
#      - URL: http://localhost:5000/dados?code=BOVAJ28&field=vencimento
#      - Retorna: Uma string com a data de vencimento (ex: "17/10/2025").
#
#    - Parâmetro 'field' para ambos: "strike-vencimento" (ou "vencimento-strike")
#      - URL: http://localhost:5000/dados?code=BOVAJ28&field=strike-vencimento
#      - Retorna: Uma string com os valores separados por pipe '|' (ex: "146,00|17/10/2025").
#
# 2. DADOS DE DIVIDENDOS
#    - Objetivo: Obter uma tabela formatada com o histórico de proventos de uma ação.
#    - Exemplo de uso no Excel (VBA): GetDividendos("petr4")
#
#    - Parâmetro 'field': "dividendos"
#      - URL: http://localhost:5000/dados?code=petr4&field=dividendos
#      - Retorna: Uma única string gigante contendo toda a tabela de proventos.
#        - As colunas são separadas por ponto e vírgula (';').
#        - As linhas são separadas por pipe ('|').
#        - Este formato é otimizado para a função TEXTSPLIT do Excel ou para ser processado em VBA.
#
# AVISO IMPORTANTE:
# O scraping de dados da web é uma técnica frágil. Se os sites de origem (Status Invest,
# Opções.net) mudarem a estrutura de seu HTML, as funções de scraping neste script
# precisarão ser atualizadas para continuarem funcionando.
#
# =================================================================================================


# Módulos nativos
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse, parse_qs
from urllib.request import urlopen, Request
import json
import re
import socket

# Módulos externos para o scraper de dividendos
import requests
from bs4 import BeautifulSoup

# ==============================================================================
# FUNÇÃO 1: SCRAPER DE OPÇÕES (opcoes.net.br)
# ==============================================================================
def parse_dados_da_opcao(codigo_opcao: str) -> dict:
    url = f"https://opcoes.net.br/{codigo_opcao.upper()}"
    print(f"[Opções] Buscando dados em: {url}")
    try:
        req = Request(url, headers={'User-Agent': 'Mozilla/5.0'})
        with urlopen(req) as response:
            html_str = response.read().decode('utf-8')
        match = re.search(r'<title>(.*?)</title>', html_str, re.IGNORECASE)
        if not match: return {"erro": "Tag <title> não encontrada."}
        title_text = match.group(1)
        partes = title_text.split(' - ')
        if len(partes) >= 3:
            return {
                "strike": partes[1].replace('Strike R$', '').strip(),
                "vencimento": partes[2].replace('Vencimento ', '').strip()
            }
        else:
            return {"erro": f"Formato do título inesperado: '{title_text}'"}
    except Exception as e:
        return {"erro": f"Falha ao buscar dados da opção: {str(e)}"}

# ==============================================================================
# FUNÇÃO 2: SCRAPER DE DIVIDENDOS (statusinvest.com.br)
# ==============================================================================
def scrape_proventos_statusinvest(ticker: str) -> list:
    url = f"https://statusinvest.com.br/acoes/{ticker.lower()}"
    print(f"[Dividendos] Buscando dados em: {url}")
    try:
        response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'})
        response.raise_for_status()
        soup = BeautifulSoup(response.content, 'html.parser')
        main_container = soup.find('div', id='earning-section')
        if not main_container: return []
        proventos_table = main_container.find('table')
        if not proventos_table: return []
        proventos_list = []
        for row in proventos_table.find('tbody').find_all('tr'):
            cols = row.find_all('td')
            proventos_list.append({
                'Tipo': cols[0].text.strip(),
                'Data Com': cols[1].text.strip(),
                'Valor': cols[3].text.strip()#.replace(',', '.')
            })
        return proventos_list
    except Exception as e:
        print(f"Erro no scraper de dividendos: {e}")
        return []

def formatar_proventos_para_textsplit(lista_proventos: list) -> str:
    """Formata a lista de proventos para ser usada com TEXTSPLIT no Excel."""
    if not lista_proventos: return ""
    col_sep = ';'
    row_sep = '|'
    linhas_formatadas = []
    for provento in lista_proventos:
        campos = ["", "", "Venda", provento['Tipo'], provento['Data Com'], "", provento['Valor']]
        linhas_formatadas.append(col_sep.join(campos))
    return row_sep.join(linhas_formatadas)

def formatar_proventos_para_textsplit2(lista_proventos: list) -> str:
    """Formata a lista de proventos para ser usada com TEXTSPLIT no Excel."""
    if not lista_proventos: 
        return ""
        
    col_sep = ';'
    row_sep = '|'
    
    # --- MODIFICAÇÃO PARA O TESTE ---
    # Pega apenas o primeiro provento da lista
    primeiro_provento = lista_proventos[0]
    
    # Formata apenas essa primeira linha
    campos = ["", "", "Venda", primeiro_provento['Tipo'], primeiro_provento['Data Com'], "", primeiro_provento['Valor']]
    linha_unica_formatada = col_sep.join(campos)
    
    # Retorna apenas a primeira linha, sem o separador '|'
    return ';;Venda;Dividendo;21/08/2025;;0.20092175|;;Venda;JCP;21/08/2025;;0.13504029|;;Venda;JCP;21/08/2025;;0.33596205|;;Venda;JCP;02/06/2025;;0.45458310|;;Venda;JCP;02/06/2025;;0.14613560|;;Venda;Dividendo;02/06/2025;;0.30844749|;;Venda;Rend. Tributado;16/04/2025;;0.02152467|;;Venda;Dividendo;16/04/2025;;0.35477261|;;Venda;Dividendo;16/04/2025;;0.35477261|;;Venda;Rend. Tributado;16/04/2025;;0.01706013|;;Venda;JCP;23/12/2024;;0.01053822|;;Venda;Rend. Tributado;23/12/2024;;0.01134886'

# ==============================================================================
# SERVIDOR HTTP
# ==============================================================================
class APIServer(BaseHTTPRequestHandler):
    def do_GET(self):
        parsed_url = urlparse(self.path)
        if parsed_url.path == '/dados': # Endpoint genérico
            params = parse_qs(parsed_url.query)
            codigo = params.get('code', [None])[0]
            field = params.get('field', [None])[0]

            if not codigo or not field:
                self._send_json_response(400, {"erro": "Os parâmetros 'code' e 'field' são obrigatórios."})
                return
            
            # --- ROTEAMENTO LÓGICO ---
            if field == 'dividendos':
                # Chama a lógica de dividendos
                dados_proventos = scrape_proventos_statusinvest(codigo)
                string_formatada = formatar_proventos_para_textsplit(dados_proventos)
                self._send_text_response(200, string_formatada)
            else:
                # Chama a lógica de opções
                dados_opcoes = parse_dados_da_opcao(codigo)
                if "erro" in dados_opcoes:
                    self._send_json_response(500, dados_opcoes)
                    return
                
                campos_lista = field.split('-')
                valores_resposta = []
                for campo in campos_lista:
                    if campo in dados_opcoes:
                        valores_resposta.append(dados_opcoes[campo])
                    else:
                        self._send_json_response(400, {"erro": f"O campo de opção '{campo}' é inválido."})
                        return
                
                self._send_text_response(200, "|".join(valores_resposta))
        else:
            self._send_json_response(404, {"erro": "Endpoint não encontrado. Use /dados"})

    def _send_json_response(self, status_code, data):
        self.send_response(status_code); self.send_header('Content-type', 'application/json'); self.end_headers()
        self.wfile.write(json.dumps(data).encode('utf-8'))
        
    def _send_text_response(self, status_code, text_data):
        self.send_response(status_code); self.send_header('Content-type', 'text/plain; charset=utf-8'); self.end_headers()
        self.wfile.write(text_data.encode('utf-8'))

def get_local_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try: s.connect(('10.255.255.255', 1)); IP = s.getsockname()[0]
    except Exception: IP = '127.0.0.1'
    finally: s.close()
    return IP

# ==============================================================================
# EXECUÇÃO DO SERVIDOR
# ==============================================================================
if __name__ == "__main__":
    PORT = 5000
    HOST_IP = 'localhost'
    httpd = HTTPServer(('', PORT), APIServer)
    
    print("="*60)
    print("Servidor de API Integrado iniciado!")
    print(f"Ouvindo em: http://{HOST_IP}:{PORT}")
    print("\n--- Exemplo para OPÇÕES ---")
    print(f"http://{HOST_IP}:{PORT}/dados?code=BOVAJ28&field=strike-vencimento")
    print("\n--- Exemplo para DIVIDENDOS ---")
    print(f"http://{HOST_IP}:{PORT}/dados?code=petr4&field=dividendos")
    print("\nPara parar o servidor, pressione CTRL+C.")
    print("="*60)
    
    try:
        httpd.serve_forever()
    except KeyboardInterrupt: pass
    httpd.server_close()
    print("\nServidor parado.")