# -*- coding: utf-8 -*-
"""
INTERFACE GRÁFICA - ROBÔ DE BALANCEAMENTO
Gerencia o portfólio e exibe informações em tempo real
"""

import tkinter as tk
from tkinter import messagebox, scrolledtext, ttk
import subprocess
import json
import os
import threading
import time
from datetime import datetime
import pytz
import sys
import logging

class BalanceamentoApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Robô de Balanceamento de Portfólio")
        self.root.geometry("1200x700")
        
        self.balanceamento_process = None
        self.timezone = pytz.timezone("America/Sao_Paulo")
        
        self.config_file = 'configuracoes_balanceamento.json'
        self.estado_file = 'portfolio_estado.json'
        self.log_file = 'log_balanceamento.log'
        
        self.criar_interface()
        self.carregar_configuracoes()
        self.iniciar_atualizar_interface()
    
    def criar_interface(self):
        """Cria os elementos da interface"""
        
        # Frame Principal
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # ====== SECTION: CONTROLES ======
        controle_frame = ttk.LabelFrame(main_frame, text="Controles", padding=10)
        controle_frame.pack(fill=tk.X, padx=0, pady=5)
        
        btn_iniciar = ttk.Button(controle_frame, text="Iniciar Robô", command=self.iniciar_robo)
        btn_iniciar.pack(side=tk.LEFT, padx=5)
        
        btn_parar = ttk.Button(controle_frame, text="Parar Robô", command=self.parar_robo)
        btn_parar.pack(side=tk.LEFT, padx=5)
        
        btn_liquidar = ttk.Button(controle_frame, text="🚨 LIQUIDAR & PARAR", command=self.liquidar_carteira_emergencia)
        btn_liquidar.pack(side=tk.LEFT, padx=5)
        
        btn_recarregar = ttk.Button(controle_frame, text="Recarregar Config", command=self.recarregar_config)
        btn_recarregar.pack(side=tk.LEFT, padx=5)
        
        btn_relatorio = ttk.Button(controle_frame, text="Atualizar Relatório", command=self.atualizar_relatorio)
        btn_relatorio.pack(side=tk.LEFT, padx=5)
        
        # ====== SECTION: CONFIGURAÇÃO ======
        config_frame = ttk.LabelFrame(main_frame, text="Configuração", padding=10)
        config_frame.pack(fill=tk.X, padx=0, pady=5)
        
        # Capital Inicial
        ttk.Label(config_frame, text="Capital Inicial ($):").grid(row=0, column=0, sticky=tk.W, padx=5)
        self.capital_var = tk.StringVar()
        ttk.Entry(config_frame, textvariable=self.capital_var, width=15).grid(row=0, column=1, sticky=tk.W, padx=5)
        
        # Variação Balanceamento
        ttk.Label(config_frame, text="Variação Balanceamento (%):").grid(row=0, column=2, sticky=tk.W, padx=5)
        self.variacao_var = tk.StringVar()
        ttk.Entry(config_frame, textvariable=self.variacao_var, width=15).grid(row=0, column=3, sticky=tk.W, padx=5)
        
        # Testnet
        self.testnet_var = tk.BooleanVar()
        ttk.Checkbutton(config_frame, text="Usar Testnet", variable=self.testnet_var).grid(row=0, column=4, padx=5)
        
        btn_salvar_config = ttk.Button(config_frame, text="Salvar Configuração", command=self.salvar_configuracao)
        btn_salvar_config.grid(row=0, column=5, padx=5)
        
        # ====== SECTION: PORTFOLIO ======
        portfolio_frame = ttk.LabelFrame(main_frame, text="Portfólio", padding=10)
        portfolio_frame.pack(fill=tk.BOTH, expand=True, padx=0, pady=5)
        
        # Notebook com abas
        notebook = ttk.Notebook(portfolio_frame)
        notebook.pack(fill=tk.BOTH, expand=True)
        
        # Aba: Moedas
        moedas_tab = ttk.Frame(notebook)
        notebook.add(moedas_tab, text="Moedas")
        
        # Treeview para moedas
        columns = ('Moeda', 'Percentual %', 'Preço Compra', 'Ativa')
        self.moedas_tree = ttk.Treeview(moedas_tab, columns=columns, height=8)
        self.moedas_tree.column('#0', width=0, stretch=tk.NO)
        self.moedas_tree.column('Moeda', anchor=tk.W, width=100)
        self.moedas_tree.column('Percentual %', anchor=tk.CENTER, width=100)
        self.moedas_tree.column('Preço Compra', anchor=tk.CENTER, width=150)
        self.moedas_tree.column('Ativa', anchor=tk.CENTER, width=80)
        
        self.moedas_tree.heading('#0', text='', anchor=tk.W)
        self.moedas_tree.heading('Moeda', text='Moeda', anchor=tk.W)
        self.moedas_tree.heading('Percentual %', text='Percentual %', anchor=tk.CENTER)
        self.moedas_tree.heading('Preço Compra', text='Preço Compra', anchor=tk.CENTER)
        self.moedas_tree.heading('Ativa', text='Ativa', anchor=tk.CENTER)
        
        self.moedas_tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # Botões para adicionar/remover moedas
        botoes_moedas = ttk.Frame(moedas_tab)
        botoes_moedas.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Button(botoes_moedas, text="Adicionar Moeda", command=self.adicionar_moeda).pack(side=tk.LEFT, padx=5)
        ttk.Button(botoes_moedas, text="Remover Moeda", command=self.remover_moeda).pack(side=tk.LEFT, padx=5)
        ttk.Button(botoes_moedas, text="Editar Moeda", command=self.editar_moeda).pack(side=tk.LEFT, padx=5)
        
        # Aba: Status
        status_tab = ttk.Frame(notebook)
        notebook.add(status_tab, text="Status")
        
        # Text widget para status
        self.status_text = scrolledtext.ScrolledText(status_tab, height=15, wrap=tk.WORD)
        self.status_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # Aba: Log
        log_tab = ttk.Frame(notebook)
        notebook.add(log_tab, text="Log")
        
        # Text widget para log
        self.log_text = scrolledtext.ScrolledText(log_tab, height=15, wrap=tk.WORD)
        self.log_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # Status bar
        self.status_var = tk.StringVar(value="Pronto")
        status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN)
        status_bar.pack(fill=tk.X, side=tk.BOTTOM)
    
    def carregar_configuracoes(self):
        """Carrega configurações do arquivo"""
        try:
            with open(self.config_file, 'r', encoding='utf-8') as f:
                config = json.load(f)
            
            self.capital_var.set(str(config.get('capital_inicial', 1000)))
            self.variacao_var.set(str(config.get('variacao_balanceamento', 2.0)))
            self.testnet_var.set(config.get('testnet', False))
            
            # Carregar moedas
            self.moedas_tree.delete(*self.moedas_tree.get_children())
            for moeda in config.get('portfolio', []):
                self.moedas_tree.insert('', 'end', values=(
                    moeda['moeda'],
                    moeda['percentual'],
                    moeda['preco_compra'],
                    "Sim" if moeda.get('ativa', True) else "Não"
                ))
            
            self.atualizar_status("Configurações carregadas")
        except Exception as e:
            messagebox.showerror("Erro", f"Erro ao carregar configurações: {e}")
    
    def salvar_configuracao(self):
        """Salva a configuração"""
        try:
            with open(self.config_file, 'r', encoding='utf-8') as f:
                config = json.load(f)
            
            config['capital_inicial'] = float(self.capital_var.get())
            config['variacao_balanceamento'] = float(self.variacao_var.get())
            config['testnet'] = self.testnet_var.get()
            
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config, f, indent=2, ensure_ascii=False)
            
            messagebox.showinfo("Sucesso", "Configuração salva com sucesso!")
            self.atualizar_status("Configuração salva")
        except Exception as e:
            messagebox.showerror("Erro", f"Erro ao salvar configuração: {e}")
    
    def adicionar_moeda(self):
        """Adiciona uma nova moeda ao portfólio"""
        dialog = tk.Toplevel(self.root)
        dialog.title("Adicionar Moeda")
        dialog.geometry("400x250")
        
        ttk.Label(dialog, text="Moeda:").pack(padx=10, pady=5)
        moeda_entry = ttk.Entry(dialog)
        moeda_entry.pack(padx=10, pady=5, fill=tk.X)
        
        ttk.Label(dialog, text="Percentual (%):").pack(padx=10, pady=5)
        percentual_entry = ttk.Entry(dialog)
        percentual_entry.pack(padx=10, pady=5, fill=tk.X)
        
        ttk.Label(dialog, text="Preço de Compra:").pack(padx=10, pady=5)
        preco_entry = ttk.Entry(dialog)
        preco_entry.pack(padx=10, pady=5, fill=tk.X)
        
        ativa_var = tk.BooleanVar(value=True)
        ttk.Checkbutton(dialog, text="Ativa", variable=ativa_var).pack(padx=10, pady=5)
        
        def salvar():
            try:
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                
                config['portfolio'].append({
                    'moeda': moeda_entry.get().upper(),
                    'percentual': float(percentual_entry.get()),
                    'preco_compra': float(preco_entry.get()),
                    'ativa': ativa_var.get()
                })
                
                with open(self.config_file, 'w', encoding='utf-8') as f:
                    json.dump(config, f, indent=2, ensure_ascii=False)
                
                self.carregar_configuracoes()
                dialog.destroy()
                messagebox.showinfo("Sucesso", "Moeda adicionada!")
            except Exception as e:
                messagebox.showerror("Erro", f"Erro ao adicionar: {e}")
        
        ttk.Button(dialog, text="Salvar", command=salvar).pack(padx=10, pady=10, fill=tk.X)
    
    def remover_moeda(self):
        """Remove a moeda selecionada"""
        selecionado = self.moedas_tree.selection()
        if not selecionado:
            messagebox.showwarning("Aviso", "Selecione uma moeda para remover")
            return
        
        item = self.moedas_tree.item(selecionado[0])
        moeda = item['values'][0]
        
        if messagebox.askyesno("Confirmar", f"Remover {moeda}?"):
            try:
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                
                config['portfolio'] = [m for m in config['portfolio'] if m['moeda'] != moeda]
                
                with open(self.config_file, 'w', encoding='utf-8') as f:
                    json.dump(config, f, indent=2, ensure_ascii=False)
                
                self.carregar_configuracoes()
                messagebox.showinfo("Sucesso", "Moeda removida!")
            except Exception as e:
                messagebox.showerror("Erro", f"Erro ao remover: {e}")
    
    def editar_moeda(self):
        """Edita a moeda selecionada"""
        selecionado = self.moedas_tree.selection()
        if not selecionado:
            messagebox.showwarning("Aviso", "Selecione uma moeda para editar")
            return
        
        item = self.moedas_tree.item(selecionado[0])
        moeda = item['values'][0]
        percentual = item['values'][1]
        preco = item['values'][2]
        
        dialog = tk.Toplevel(self.root)
        dialog.title(f"Editar {moeda}")
        dialog.geometry("400x200")
        
        ttk.Label(dialog, text=f"Moeda: {moeda}").pack(padx=10, pady=5)
        
        ttk.Label(dialog, text="Percentual (%):").pack(padx=10, pady=5)
        percentual_entry = ttk.Entry(dialog)
        percentual_entry.insert(0, str(percentual))
        percentual_entry.pack(padx=10, pady=5, fill=tk.X)
        
        ttk.Label(dialog, text="Preço de Compra:").pack(padx=10, pady=5)
        preco_entry = ttk.Entry(dialog)
        preco_entry.insert(0, str(preco))
        preco_entry.pack(padx=10, pady=5, fill=tk.X)
        
        def salvar():
            try:
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                
                for m in config['portfolio']:
                    if m['moeda'] == moeda:
                        m['percentual'] = float(percentual_entry.get())
                        m['preco_compra'] = float(preco_entry.get())
                        break
                
                with open(self.config_file, 'w', encoding='utf-8') as f:
                    json.dump(config, f, indent=2, ensure_ascii=False)
                
                self.carregar_configuracoes()
                dialog.destroy()
                messagebox.showinfo("Sucesso", "Moeda atualizada!")
            except Exception as e:
                messagebox.showerror("Erro", f"Erro ao editar: {e}")
        
        ttk.Button(dialog, text="Salvar", command=salvar).pack(padx=10, pady=10, fill=tk.X)
    
    def iniciar_robo(self):
        """Inicia o robô"""
        if self.balanceamento_process is None:
            self.balanceamento_process = subprocess.Popen(["python", "robo_balanceamento.py"])
            messagebox.showinfo("Sucesso", "Robô iniciado!")
            self.atualizar_status("Robô em execução")
        else:
            messagebox.showwarning("Aviso", "Robô já está em execução")
    
    def parar_robo(self):
        """Para o robô"""
        if self.balanceamento_process is not None:
            self.balanceamento_process.terminate()
            self.balanceamento_process = None
            messagebox.showinfo("Sucesso", "Robô parado!")
            self.atualizar_status("Robô parado")
        else:
            messagebox.showwarning("Aviso", "Robô não está em execução")
    
    def liquidar_carteira_emergencia(self):
        """
        Função de emergência para vender TODA a carteira e parar o robô
        Requer confirmação dupla do usuário
        """
        # Primeira confirmação
        confirmar_1 = messagebox.askyesno(
            "CONFIRMAÇÃO DE RISCO #1",
            "⚠️ TEM CERTEZA QUE QUER VENDER TODA A CARTEIRA?\n\n"
            "Esta ação vendará TODAS as moedas imediatamente!\n\n"
            "Clique SIM para confirmar novamente..."
        )
        
        if not confirmar_1:
            self.atualizar_status("Liquidação cancelada")
            return
        
        # Segunda confirmação (dupla verificação)
        confirmar_2 = messagebox.askyesno(
            "CONFIRMAÇÃO DE RISCO #2",
            "⚠️ CONFIRMAÇÃO FINAL: VENDER TODA A CARTEIRA AGORA?\n\n"
            "Clique SIM para executar a liquidação de emergência:\n"
            "• Todas as moedas serão vendidas\n"
            "• O robô será parado\n"
            "• A operação é irreversível"
        )
        
        if not confirmar_2:
            self.atualizar_status("Liquidação cancelada")
            return
        
        # Executar liquidação em thread separada para não travar interface
        thread = threading.Thread(target=self._executar_liquidacao_emergencia)
        thread.daemon = True
        thread.start()
    
    def _executar_liquidacao_emergencia(self):
        """Thread worker para execução da liquidação"""
        try:
            self.atualizar_status("⏳ Iniciando liquidação de emergência...")
            
            # Importar funções necessárias do robo_balanceamento
            sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
            from robo_balanceamento import (
                obter_saldo, obter_preco_atual, executar_ordem,
                MOEDA_BASE, log_info, log_erro, log_sucesso
            )
            
            # Ler estado do portfólio
            if not os.path.exists(self.estado_file):
                self.atualizar_status("❌ Arquivo de estado não encontrado")
                messagebox.showerror("Erro", "Arquivo portfolio_estado.json não encontrado")
                return
            
            with open(self.estado_file, 'r', encoding='utf-8') as f:
                estado = json.load(f)
            
            moedas_compradas = estado.get('moedas_compradas', [])
            
            if not moedas_compradas:
                self.atualizar_status("✓ Carteira vazia, nada para vender")
                messagebox.showinfo("Info", "Nenhuma moeda para vender")
                return
            
            timestamp = datetime.now(self.timezone).strftime("%d/%m/%Y %H:%M:%S")
            log_info(f"\n{'='*60}")
            log_info(f"{'='*60}")
            log_info(f"🚨 LIQUIDAÇÃO DE EMERGÊNCIA INICIADA: {timestamp}")
            log_info(f"{'='*60}")
            log_info(f"Moedas a vender: {', '.join(moedas_compradas)}")
            log_info(f"{'='*60}\n")
            
            vendas_bem_sucedidas = 0
            vendas_falhadas = 0
            saldo_usdt_inicial = obter_saldo(MOEDA_BASE)
            
            # Vender cada moeda
            for idx, moeda in enumerate(moedas_compradas, 1):
                try:
                    self.atualizar_status(f"⏳ Vendendo {moeda} [{idx}/{len(moedas_compradas)}]...")
                    
                    symbol = f"{moeda}/{MOEDA_BASE}"
                    saldo = obter_saldo(moeda)
                    
                    if saldo <= 0:
                        log_info(f"⏭️  {moeda}: Saldo zerado, pulando...")
                        continue
                    
                    preco = obter_preco_atual(symbol)
                    if not preco:
                        log_erro(f"❌ {moeda}: Não consegui obter preço")
                        vendas_falhadas += 1
                        continue
                    
                    valor_total = saldo * preco
                    log_info(f"📊 {moeda}: Saldo={saldo:.8f} | Preço={preco:.8f} | Valor=${valor_total:.2f}")
                    
                    # Executar ordem de venda
                    ordem = executar_ordem(symbol, 'sell', saldo)
                    
                    if ordem:
                        log_sucesso(f"✓ {moeda} VENDIDO com sucesso (ID: {ordem.get('id', 'N/A')})")
                        vendas_bem_sucedidas += 1
                    else:
                        log_erro(f"❌ {moeda}: Falha ao executar venda")
                        vendas_falhadas += 1
                    
                    # Pequeno delay entre vendas para evitar throttling
                    time.sleep(1)
                    
                except Exception as e:
                    log_erro(f"❌ Erro ao vender {moeda}: {str(e)}")
                    vendas_falhadas += 1
            
            # Saldo final
            time.sleep(2)  # Aguardar processamento
            saldo_usdt_final = obter_saldo(MOEDA_BASE)
            diferenca = saldo_usdt_final - saldo_usdt_inicial
            
            # Log de resumo
            log_info(f"\n{'='*60}")
            log_info(f"📋 RESUMO DA LIQUIDAÇÃO DE EMERGÊNCIA")
            log_info(f"{'='*60}")
            log_info(f"Moedas vendidas com sucesso: {vendas_bem_sucedidas}")
            log_info(f"Moedas com falha: {vendas_falhadas}")
            log_info(f"Saldo USDT inicial: ${saldo_usdt_inicial:.2f}")
            log_info(f"Saldo USDT final: ${saldo_usdt_final:.2f}")
            log_info(f"Diferença (moedas vendidas): +${diferenca:.2f}")
            log_info(f"{'='*60}\n")
            
            # Parar o robô
            self.atualizar_status("⏳ Parando o robô...")
            self.parar_robo()
            
            # Limpar arquivos de estado e log
            self.atualizar_status("⏳ Limpando arquivos de estado...")
            arquivos_deletados = []
            
            try:
                if os.path.exists(self.estado_file):
                    os.remove(self.estado_file)
                    log_info(f"🗑️  Arquivo deletado: {self.estado_file}")
                    arquivos_deletados.append(self.estado_file)
            except Exception as e:
                log_erro(f"Aviso: Não consegui deletar {self.estado_file}: {e}")
            
            try:
                if os.path.exists(self.log_file):
                    os.remove(self.log_file)
                    log_info(f"🗑️  Arquivo deletado: {self.log_file}")
                    arquivos_deletados.append(self.log_file)
            except Exception as e:
                log_erro(f"Aviso: Não consegui deletar {self.log_file}: {e}")
            
            log_info(f"\n✓ Limpeza concluída: {len(arquivos_deletados)} arquivo(s) deletado(s)\n")
            
            self.atualizar_status("✓ Liquidação concluída, robô parado e arquivos deletados")
            messagebox.showinfo(
                "Liquidação Concluída",
                f"✓ Moedas vendidas: {vendas_bem_sucedidas}\n"
                f"❌ Falhas: {vendas_falhadas}\n"
                f"Saldo USDT recebido: +${diferenca:.2f}\n\n"
                f"Robô foi parado.\n\n"
                f"Arquivos deletados: {', '.join(arquivos_deletados) if arquivos_deletados else 'Nenhum'}"
            )
            
        except Exception as e:
            erro_msg = f"Erro durante liquidação: {str(e)}"
            log_erro(erro_msg)
            self.atualizar_status(f"❌ Erro: {erro_msg}")
            messagebox.showerror("Erro na Liquidação", erro_msg)
    
    def recarregar_config(self):
        """Recarrega as configurações"""
        self.carregar_configuracoes()
        messagebox.showinfo("Sucesso", "Configurações recarregadas!")
    
    def atualizar_relatorio(self):
        """Atualiza o relatório do portfólio"""
        try:
            if os.path.exists(self.estado_file):
                with open(self.estado_file, 'r', encoding='utf-8') as f:
                    estado = json.load(f)
                
                info = f"""
ESTADO DO PORTFÓLIO
{"=" * 50}
Fase: {estado.get('fase', 'N/A').upper()}
Data de Início: {estado.get('data_inicio', 'N/A')}
Capital Inicial: {estado.get('capital_inicial', 'N/A')}

Moedas Compradas: {', '.join(estado.get('moedas_compradas', []))}
Moedas Pendentes: {', '.join(estado.get('moedas_pendentes', []))}

Percentuais Alvo: {estado.get('percentuais_alvo', {})}
Preços de Compra: {estado.get('precos_compra', {})}

Total de Trades: {len(estado.get('historico_trades', []))}
"""
                
                self.status_text.delete(1.0, tk.END)
                self.status_text.insert(tk.END, info)
                self.atualizar_status("Relatório atualizado")
            else:
                self.status_text.delete(1.0, tk.END)
                self.status_text.insert(tk.END, "Portfólio não inicializado ainda")
        except Exception as e:
            messagebox.showerror("Erro", f"Erro ao atualizar relatório: {e}")
    
    def atualizar_status(self, mensagem):
        """Atualiza a barra de status"""
        timestamp = datetime.now(self.timezone).strftime("%H:%M:%S")
        self.status_var.set(f"[{timestamp}] {mensagem}")
    
    def iniciar_atualizar_interface(self):
        """Atualiza a interface periodicamente"""
        def atualizar():
            try:
                if os.path.exists(self.log_file):
                    with open(self.log_file, 'r', encoding='utf-8') as f:
                        log_content = f.read()
                    
                    self.log_text.delete(1.0, tk.END)
                    self.log_text.insert(tk.END, log_content)
                    self.log_text.see(tk.END)
            except Exception:
                pass
            
            self.root.after(2000, atualizar)
        
        atualizar()

def main():
    root = tk.Tk()
    app = BalanceamentoApp(root)
    root.mainloop()

if __name__ == "__main__":
    main()
