# automation/delegation_bot.py

import time
import threading
import logging
from blockchain.trx_interaction import TRXInteraction
from database.db_manager import DBManager
from utils.helpers import select_best_sr
import config.settings as settings

class DelegationBot:
    def __init__(self):
        self.trx_interaction = TRXInteraction()
        self.db_manager = DBManager()
        self._stop_event = threading.Event()
        self.processing_transaction = False

    def run(self):
        logging.info('Bot de delegação iniciado.')
        while not self._stop_event.is_set():
            try:
                self.check_and_delegate()
                self.collect_rewards()  # Adicionado para coletar recompensas
            except Exception as e:
                logging.error(f'Erro durante a execução do bot: {e}')
            for _ in range(3600):  # Esperar por uma hora
                if self._stop_event.is_set():
                    break
                time.sleep(1)
        logging.info('Bot de delegação parado.')

    def check_and_delegate(self):
        self.processing_transaction = True
        balance = self.trx_interaction.get_balance()
        if balance is None:
            logging.error('Não foi possível obter o saldo. Tentando novamente na próxima iteração.')
            self.processing_transaction = False
            return

        logging.info(f'Saldo atual: {balance} TRX')

        minimum_balance = settings.MINIMUM_BALANCE
        reinvest_threshold = settings.REINVEST_THRESHOLD

        if balance >= minimum_balance + reinvest_threshold:
            best_sr = select_best_sr()
            amount_to_delegate = balance - minimum_balance
            result = self.trx_interaction.delegate_trx(best_sr, amount_to_delegate)
            if result and result['result']:
                self.db_manager.add_delegation(best_sr, amount_to_delegate)
                self.db_manager.update_account_metrics(invested=amount_to_delegate)
                logging.info(f'Delegado {amount_to_delegate} TRX para {best_sr}')
            else:
                logging.error('Falha na delegação.')
        else:
            logging.info('Saldo insuficiente para delegação.')

        self.processing_transaction = False

    def collect_rewards(self):
        # Implementação da lógica para coletar recompensas
        # Exemplo: Verificar o saldo atual e subtrair o total investido para obter as recompensas
        balance = self.trx_interaction.get_balance()
        if balance is None:
            logging.error('Não foi possível obter o saldo para coletar recompensas.')
            return

        metrics = self.db_manager.get_account_metrics()
        if metrics:
            expected_balance = metrics.total_invested + metrics.total_rewards
            rewards = balance - expected_balance
            if rewards > 0:
                self.db_manager.add_reward(rewards)
                self.db_manager.update_account_metrics(rewards=rewards)
                logging.info(f'Novas recompensas coletadas: {rewards} TRX')
            else:
                logging.info('Nenhuma nova recompensa detectada.')
        else:
            logging.info('Métricas da conta indisponíveis para coletar recompensas.')

# backend/flask_server.py

from flask import Flask, jsonify
from database.db_manager import DBManager
from blockchain.trx_interaction import TRXInteraction
from config.settings import FLASK_HOST, FLASK_PORT

app = Flask(__name__)
db_manager = DBManager()
trx_interaction = TRXInteraction()

@app.route('/balance')
def get_balance():
    balance = trx_interaction.get_balance()
    return jsonify({'balance': balance})

@app.route('/delegations')
def get_delegations():
    delegations = db_manager.get_delegations()
    data = [{'sr_address': d.sr_address, 'amount': d.amount, 'timestamp': d.timestamp.isoformat()} for d in delegations]
    return jsonify(data)

@app.route('/rewards')
def get_rewards():
    rewards = db_manager.get_rewards()
    data = [{'amount': r.amount, 'timestamp': r.timestamp.isoformat()} for r in rewards]
    return jsonify(data)

@app.route('/metrics')
def get_metrics():
    metrics = db_manager.get_account_metrics()
    data = {
        'total_invested': metrics.total_invested if metrics else 0,
        'total_rewards': metrics.total_rewards if metrics else 0,
        'current_balance': metrics.current_balance if metrics else 0,
        'timestamp': metrics.timestamp.isoformat() if metrics else None
    }
    return jsonify(data)

if __name__ == '__main__':
    app.run(host=FLASK_HOST, port=FLASK_PORT)


from tronpy import Tron
from tronpy.keys import PrivateKey
from tronpy.providers import HTTPProvider
import config.settings as settings
from tronpy.exceptions import TaposError  # Altere para 'TaposError'

class TRXInteraction:
    def __init__(self):
        self.update_client()

    def update_client(self):
        try:
            provider = HTTPProvider(endpoint_uri=settings.TRON_NODE_URL)
            self.client = Tron(provider=provider)
        except Exception as e:
            print(f'Erro ao conectar ao nó TRON: {e}')
            self.client = None
            return

        try:
            self.private_key = PrivateKey(bytes.fromhex(settings.PRIVATE_KEY))
        except Exception as e:
            self.private_key = None
            print(f'Chave privada inválida: {e}')

        self.wallet_address = settings.WALLET_ADDRESS

    def get_balance(self):
        if not self.client:
            self.update_client()
        if not self.client:
            print('Cliente TRON não está disponível.')
            return None
        if not self.wallet_address:
            print('Endereço da carteira não está definido.')
            return None
        try:
            balance = self.client.get_account_balance(self.wallet_address)
            balance_trx = balance / 1_000_000
            return balance_trx
        except TaposError as e:
            print(f'Erro ao obter o saldo: {e}')
            return None
        except Exception as e:
            print(f'Erro inesperado ao obter o saldo: {e}')
            return None
        

    def delegate_trx(self, sr_address, amount):
        if not self.client:
            self.update_client()
        if not self.client:
            print('Cliente TRON não está disponível.')
            return None
        if not self.private_key or not self.wallet_address:
            print('Chave privada ou endereço da carteira não estão definidos.')
            return None
        try:
            txn = (
                self.client.trx.freeze_balance(
                    amount=int(amount * 1_000_000),
                    resource='ENERGY',
                    receiver=sr_address
                )
                .build()
                .sign(self.private_key)
            )
            result = txn.broadcast().wait()
            return result
        except TaposError as e:  
            print(f'Erro ao delegar TRX: {e}')
            return None
        except Exception as e:
            print(f'Erro inesperado ao delegar TRX: {e}')
            return None


# config/settings.py

# Inicialização das variáveis de configuração
TRON_NODE_URL = 'https://api.trongrid.io'  # URL correta para o nó TRON público
PRIVATE_KEY = None
WALLET_ADDRESS = None
MINIMUM_BALANCE = 100.0
REINVEST_THRESHOLD = 10.0
FLASK_HOST = '127.0.0.1'
FLASK_PORT = 5000
DATABASE_URI = 'sqlite:///database/cryptovoid.db'

# Função para atualizar as configurações em tempo de execução
def update_settings(tron_node_url=None, private_key=None, wallet_address=None,
                    minimum_balance=None, reinvest_threshold=None, flask_host=None, flask_port=None,
                    database_uri=None):
    global TRON_NODE_URL, PRIVATE_KEY, WALLET_ADDRESS, MINIMUM_BALANCE, REINVEST_THRESHOLD, FLASK_HOST, FLASK_PORT, DATABASE_URI
    if tron_node_url is not None:
        TRON_NODE_URL = tron_node_url
    if private_key is not None:
        PRIVATE_KEY = private_key
    if wallet_address is not None:
        WALLET_ADDRESS = wallet_address
    if minimum_balance is not None:
        MINIMUM_BALANCE = float(minimum_balance)
    if reinvest_threshold is not None:
        REINVEST_THRESHOLD = float(reinvest_threshold)
    if flask_host is not None:
        FLASK_HOST = flask_host
    if flask_port is not None:
        FLASK_PORT = int(flask_port)
    if database_uri is not None:
        DATABASE_URI = database_uri


# database/db_manager.py

from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime, func
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from config.settings import DATABASE_URI
from datetime import datetime
import csv
import os

Base = declarative_base()

class Delegation(Base):
    __tablename__ = 'delegations'
    id = Column(Integer, primary_key=True)
    sr_address = Column(String)
    amount = Column(Float)
    timestamp = Column(DateTime, default=datetime.utcnow)

class Reward(Base):
    __tablename__ = 'rewards'
    id = Column(Integer, primary_key=True)
    amount = Column(Float)
    timestamp = Column(DateTime, default=datetime.utcnow)

class AccountMetric(Base):
    __tablename__ = 'account_metrics'
    id = Column(Integer, primary_key=True)
    total_invested = Column(Float)
    total_rewards = Column(Float)
    current_balance = Column(Float)
    timestamp = Column(DateTime, default=datetime.utcnow)

class DBManager:
    def __init__(self):
        self.engine = create_engine(DATABASE_URI)
        Base.metadata.create_all(self.engine)
        self.Session = sessionmaker(bind=self.engine)

    # Métodos para Delegations
    def add_delegation(self, sr_address, amount):
        session = self.Session()
        delegation = Delegation(sr_address=sr_address, amount=amount)
        session.add(delegation)
        session.commit()
        session.close()

    def get_delegations(self):
        session = self.Session()
        delegations = session.query(Delegation).order_by(Delegation.timestamp.desc()).all()
        session.close()
        return delegations

    # Métodos para Rewards
    def add_reward(self, amount):
        session = self.Session()
        reward = Reward(amount=amount)
        session.add(reward)
        session.commit()
        session.close()

    def get_rewards(self):
        session = self.Session()
        rewards = session.query(Reward).order_by(Reward.timestamp.desc()).all()
        session.close()
        return rewards

    # Métodos para AccountMetrics
    def get_account_metrics(self):
        session = self.Session()
        metrics = session.query(AccountMetric).order_by(AccountMetric.timestamp.desc()).first()
        session.close()
        return metrics

    def update_account_metrics(self, invested=None, rewards=None, balance=None):
        session = self.Session()
        metrics = self.get_account_metrics()
        if not metrics:
            metrics = AccountMetric(total_invested=0, total_rewards=0, current_balance=0)
            session.add(metrics)

        if invested is not None:
            metrics.total_invested += invested
        if rewards is not None:
            metrics.total_rewards += rewards
        if balance is not None:
            metrics.current_balance = balance
        metrics.timestamp = datetime.utcnow()
        session.commit()
        session.close()

    # Métodos para exportar e importar perfil
    def export_profile(self, dir_path):
        session = self.Session()
        try:
            # Exportar delegações
            delegations = session.query(Delegation).all()
            with open(os.path.join(dir_path, 'delegations.csv'), 'w', newline='', encoding='utf-8') as csvfile:
                writer = csv.writer(csvfile)
                writer.writerow(['id', 'sr_address', 'amount', 'timestamp'])
                for d in delegations:
                    writer.writerow([d.id, d.sr_address, d.amount, d.timestamp.isoformat()])

            # Exportar recompensas
            rewards = session.query(Reward).all()
            with open(os.path.join(dir_path, 'rewards.csv'), 'w', newline='', encoding='utf-8') as csvfile:
                writer = csv.writer(csvfile)
                writer.writerow(['id', 'amount', 'timestamp'])
                for r in rewards:
                    writer.writerow([r.id, r.amount, r.timestamp.isoformat()])

            # Exportar métricas da conta
            metrics = session.query(AccountMetric).all()
            with open(os.path.join(dir_path, 'account_metrics.csv'), 'w', newline='', encoding='utf-8') as csvfile:
                writer = csv.writer(csvfile)
                writer.writerow(['id', 'total_invested', 'total_rewards', 'current_balance', 'timestamp'])
                for m in metrics:
                    writer.writerow([m.id, m.total_invested, m.total_rewards, m.current_balance, m.timestamp.isoformat()])
        finally:
            session.close()

    def import_profile(self, dir_path):
        session = self.Session()
        try:
            # Importar delegações
            with open(os.path.join(dir_path, 'delegations.csv'), 'r', newline='', encoding='utf-8') as csvfile:
                reader = csv.DictReader(csvfile)
                for row in reader:
                    delegation = Delegation(
                        id=int(row['id']),
                        sr_address=row['sr_address'],
                        amount=float(row['amount']),
                        timestamp=datetime.fromisoformat(row['timestamp'])
                    )
                    session.merge(delegation)

            # Importar recompensas
            with open(os.path.join(dir_path, 'rewards.csv'), 'r', newline='', encoding='utf-8') as csvfile:
                reader = csv.DictReader(csvfile)
                for row in reader:
                    reward = Reward(
                        id=int(row['id']),
                        amount=float(row['amount']),
                        timestamp=datetime.fromisoformat(row['timestamp'])
                    )
                    session.merge(reward)

            # Importar métricas da conta
            with open(os.path.join(dir_path, 'account_metrics.csv'), 'r', newline='', encoding='utf-8') as csvfile:
                reader = csv.DictReader(csvfile)
                for row in reader:
                    metric = AccountMetric(
                        id=int(row['id']),
                        total_invested=float(row['total_invested']),
                        total_rewards=float(row['total_rewards']),
                        current_balance=float(row['current_balance']),
                        timestamp=datetime.fromisoformat(row['timestamp'])
                    )
                    session.merge(metric)

            session.commit()
        finally:
            session.close()


# gui/dashboard_page.py

from PyQt5.QtWidgets import QWidget, QLabel, QVBoxLayout, QHBoxLayout, QSizePolicy
from PyQt5.QtGui import QPalette, QColor, QFont
from PyQt5.QtCore import Qt, QTimer
import requests
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.dates as mdates
from datetime import datetime
import matplotlib.pyplot as plt

class DashboardPage(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.load_data()

    def init_ui(self):
        # Aplicando o tema escuro
        self.setAutoFillBackground(True)
        palette = self.palette()
        palette.setColor(QPalette.Window, QColor(40, 40, 40))  # Fundo cinza escuro
        self.setPalette(palette)

        layout = QVBoxLayout()

        # Labels de métricas
        metrics_layout = QHBoxLayout()

        label_style = "color: white; font-size: 16px;"
        self.total_invested_label = QLabel('Total Investido: Atualizando...')
        self.total_invested_label.setStyleSheet(label_style)
        self.total_rewards_label = QLabel('Total de Recompensas: Atualizando...')
        self.total_rewards_label.setStyleSheet(label_style)
        self.current_balance_label = QLabel('Saldo Atual: Atualizando...')
        self.current_balance_label.setStyleSheet(label_style)

        metrics_layout.addWidget(self.total_invested_label)
        metrics_layout.addWidget(self.total_rewards_label)
        metrics_layout.addWidget(self.current_balance_label)

        # Gráficos
        self.figure = Figure(facecolor='#282828')  # Fundo da figura no mesmo tom
        self.canvas = FigureCanvas(self.figure)
        self.canvas.setStyleSheet("background-color: transparent;")

        # Ajuste do tamanho do gráfico
        self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        # Atualizar dados periodicamente
        self.timer = QTimer()
        self.timer.timeout.connect(self.load_data)
        self.timer.start(60000)  # Atualiza a cada minuto

        layout.addLayout(metrics_layout)
        layout.addWidget(self.canvas)
        self.setLayout(layout)

    def load_data(self):
        # Obter métricas
        try:
            metrics_response = requests.get('http://127.0.0.1:5000/metrics')
            metrics = metrics_response.json()
            self.total_invested_label.setText(f'Total Investido: {metrics["total_invested"]} TRX')
            self.total_rewards_label.setText(f'Total de Recompensas: {metrics["total_rewards"]} TRX')
            self.current_balance_label.setText(f'Saldo Atual: {metrics["current_balance"]} TRX')
        except Exception as e:
            print(f'Erro ao obter métricas: {e}')

        # Obter dados para o gráfico
        try:
            rewards_response = requests.get('http://127.0.0.1:5000/rewards')
            rewards_data = rewards_response.json()

            # Preparar dados do gráfico
            dates = []
            amounts = []
            for r in rewards_data:
                try:
                    date = datetime.fromisoformat(r['timestamp'])
                    dates.append(date)
                    amounts.append(r['amount'])
                except ValueError as e:
                    print(f'Erro ao processar timestamp: {e}')

            # Limpar a figura anterior
            self.figure.clear()

            # Criar o gráfico
            ax = self.figure.add_subplot(111)
            ax.plot(dates, amounts, marker='o', color='#00FF00')  # Linha verde
            ax.set_title('Recompensas ao Longo do Tempo', color='white')
            ax.set_xlabel('Data', color='white')
            ax.set_ylabel('Recompensa (TRX)', color='white')
            ax.tick_params(axis='x', colors='white')
            ax.tick_params(axis='y', colors='white')
            ax.xaxis.set_major_formatter(mdates.DateFormatter('%d/%m/%Y %H:%M'))
            ax.xaxis.set_major_locator(mdates.AutoDateLocator())
            ax.grid(True, color='#444444')

            # Definir cor de fundo do eixo
            ax.set_facecolor('#282828')

            self.figure.autofmt_xdate()

            # Atualizar o canvas
            self.canvas.draw()
        except Exception as e:
            print(f'Erro ao carregar dados do gráfico: {e}')


# gui/delegation_page.py

from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QVBoxLayout, QLineEdit, QMessageBox
from PyQt5.QtGui import QPalette, QColor
from PyQt5.QtCore import Qt
import requests
from config.settings import FLASK_HOST, FLASK_PORT
from blockchain.trx_interaction import TRXInteraction
from database.db_manager import DBManager
from utils.helpers import select_best_sr

class DelegationPage(QWidget):
    def __init__(self):
        super().__init__()
        self.trx_interaction = TRXInteraction()
        self.db_manager = DBManager()
        self.init_ui()
        self.update_balance()

    def init_ui(self):
        # Aplicando o tema escuro
        self.setAutoFillBackground(True)
        palette = self.palette()
        palette.setColor(QPalette.Window, QColor(40, 40, 40))  # Fundo cinza escuro
        self.setPalette(palette)

        layout = QVBoxLayout()

        # Estilo
        label_style = "color: white; font-size: 16px;"
        button_style = """
            QPushButton {
                background-color: #0055FF;
                color: white;
                font-size: 14px;
                padding: 8px 16px;
                border-radius: 5px;
            }
            QPushButton:hover {
                background-color: #003EB8;
            }
        """
        input_style = """
            QLineEdit {
                background-color: #303030;
                color: white;
                padding: 5px;
                border: 1px solid #555555;
                border-radius: 3px;
            }
        """

        self.balance_label = QLabel('Saldo: Atualizando...')
        self.balance_label.setStyleSheet(label_style)

        self.update_balance_button = QPushButton('Atualizar Saldo')
        self.update_balance_button.setStyleSheet(button_style)
        self.update_balance_button.clicked.connect(self.update_balance)

        # Campo para quantidade de TRX a delegar
        self.amount_label = QLabel('Quantidade a Delegar (TRX):')
        self.amount_label.setStyleSheet(label_style)
        self.amount_input = QLineEdit()
        self.amount_input.setStyleSheet(input_style)
        self.amount_input.setMaximumWidth(200)  # Limitar largura do input

        # Botão de Delegação Manual
        self.delegate_button = QPushButton('Delegar Manualmente')
        self.delegate_button.setStyleSheet(button_style)
        self.delegate_button.clicked.connect(self.manual_delegate)

        layout.addWidget(self.balance_label, alignment=Qt.AlignCenter)
        layout.addWidget(self.update_balance_button, alignment=Qt.AlignCenter)
        layout.addSpacing(20)
        layout.addWidget(self.amount_label, alignment=Qt.AlignCenter)
        layout.addWidget(self.amount_input, alignment=Qt.AlignCenter)
        layout.addWidget(self.delegate_button, alignment=Qt.AlignCenter)
        layout.addStretch()
        self.setLayout(layout)

    def update_balance(self):
        try:
            response = requests.get(f'http://{FLASK_HOST}:{FLASK_PORT}/balance')
            balance = response.json()['balance']
            self.balance_label.setText(f'Saldo: {balance} TRX')
        except Exception as e:
            self.balance_label.setText('Erro ao obter o saldo.')
            print(f'Erro ao atualizar saldo: {e}')

    def manual_delegate(self):
        amount_text = self.amount_input.text()
        if not amount_text or not amount_text.replace('.', '', 1).isdigit():
            QMessageBox.warning(self, 'Erro', 'Por favor, insira um valor numérico válido.')
            return

        amount = float(amount_text)
        if amount <= 0:
            QMessageBox.warning(self, 'Erro', 'A quantidade a delegar deve ser maior que zero.')
            return

        # Obter o melhor Super Representante (SR)
        best_sr = select_best_sr()
        if not best_sr:
            QMessageBox.warning(self, 'Erro', 'Não foi possível determinar o melhor SR.')
            return

        # Realizar a delegação
        result = self.trx_interaction.delegate_trx(best_sr, amount)
        if result and result.get('result'):
            self.db_manager.add_delegation(best_sr, amount)
            QMessageBox.information(self, 'Delegação Realizada', f'Delegado {amount} TRX para {best_sr} com sucesso.')
            self.update_balance()
            self.amount_input.clear()
        else:
            QMessageBox.warning(self, 'Erro', 'Falha ao realizar a delegação.')


# gui/history_page.py

from PyQt5.QtWidgets import QWidget, QVBoxLayout, QTableWidget, QTableWidgetItem, QLabel
from PyQt5.QtGui import QPalette, QColor, QFont
from PyQt5.QtCore import Qt
import requests
from config.settings import FLASK_HOST, FLASK_PORT
from datetime import datetime


class HistoryPage(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.load_data()

    def init_ui(self):
        # Aplicando o tema escuro
        self.setAutoFillBackground(True)
        palette = self.palette()
        palette.setColor(QPalette.Window, QColor(40, 40, 40))
        self.setPalette(palette)

        layout = QVBoxLayout()

        # Estilos
        label_style = "color: white; font-size: 18px; font-weight: bold;"
        table_style = """
            QTableWidget {
                background-color: #303030;
                color: white;
                border: none;
            }
            QHeaderView::section {
                background-color: #404040;
                color: white;
            }
            QTableWidget::item {
                border-bottom: 1px solid #555555;
            }
        """

        # Tabela de Delegações
        self.delegations_label = QLabel('Histórico de Delegações')
        self.delegations_label.setStyleSheet(label_style)
        self.delegations_table = QTableWidget()
        self.delegations_table.setColumnCount(3)
        self.delegations_table.setHorizontalHeaderLabels(['Endereço SR', 'Quantidade (TRX)', 'Data'])
        self.delegations_table.horizontalHeader().setStretchLastSection(True)
        self.delegations_table.setStyleSheet(table_style)

        # Tabela de Recompensas
        self.rewards_label = QLabel('Histórico de Recompensas')
        self.rewards_label.setStyleSheet(label_style)
        self.rewards_table = QTableWidget()
        self.rewards_table.setColumnCount(2)
        self.rewards_table.setHorizontalHeaderLabels(['Quantidade (TRX)', 'Data'])
        self.rewards_table.horizontalHeader().setStretchLastSection(True)
        self.rewards_table.setStyleSheet(table_style)

        layout.addWidget(self.delegations_label, alignment=Qt.AlignCenter)
        layout.addWidget(self.delegations_table)
        layout.addSpacing(20)
        layout.addWidget(self.rewards_label, alignment=Qt.AlignCenter)
        layout.addWidget(self.rewards_table)
        layout.addStretch()
        self.setLayout(layout)

    def load_data(self):
        # Carregar histórico de delegações
        try:
            delegations_response = requests.get(f'http://{FLASK_HOST}:{FLASK_PORT}/delegations')
            delegations = delegations_response.json()
            self.delegations_table.setRowCount(len(delegations))
            for row, delegation in enumerate(delegations):
                self.delegations_table.setItem(row, 0, QTableWidgetItem(delegation['sr_address']))
                self.delegations_table.setItem(row, 1, QTableWidgetItem(str(delegation['amount'])))
                # Formatar a data
                date = datetime.fromisoformat(delegation['timestamp']).strftime('%d/%m/%Y %H:%M')
                self.delegations_table.setItem(row, 2, QTableWidgetItem(date))
        except Exception as e:
            print(f'Erro ao carregar delegações: {e}')

        # Carregar histórico de recompensas
        try:
            rewards_response = requests.get(f'http://{FLASK_HOST}:{FLASK_PORT}/rewards')
            rewards = rewards_response.json()
            self.rewards_table.setRowCount(len(rewards))
            for row, reward in enumerate(rewards):
                self.rewards_table.setItem(row, 0, QTableWidgetItem(str(reward['amount'])))
                # Formatar a data
                date = datetime.fromisoformat(reward['timestamp']).strftime('%d/%m/%Y %H:%M')
                self.rewards_table.setItem(row, 1, QTableWidgetItem(date))
        except Exception as e:
            print(f'Erro ao carregar recompensas: {e}')


# gui/main_window.py

from PyQt5.QtWidgets import QMainWindow, QAction, QStackedWidget
from PyQt5.QtGui import QIcon, QPalette, QColor
from gui.delegation_page import DelegationPage
from gui.history_page import HistoryPage
from gui.settings_page import SettingsPage
from gui.dashboard_page import DashboardPage

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('CriptoVoid TRX Farming')
        self.setGeometry(100, 100, 1000, 700)
        self.create_menu()
        self.init_ui()

        # Aplicando o tema escuro ao MainWindow
        self.setAutoFillBackground(True)
        palette = self.palette()
        palette.setColor(QPalette.Window, QColor(30, 30, 30))  # Fundo um pouco mais escuro
        self.setPalette(palette)

    def create_menu(self):
        menu = self.menuBar()
        menu.setStyleSheet("background-color: #282828; color: white;")

        dashboard_action = QAction('Dashboard', self)
        dashboard_action.triggered.connect(self.show_dashboard_page)
        delegation_action = QAction('Delegação', self)
        delegation_action.triggered.connect(self.show_delegation_page)
        history_action = QAction('Histórico', self)
        history_action.triggered.connect(self.show_history_page)
        settings_action = QAction('Configurações', self)
        settings_action.triggered.connect(self.show_settings_page)

        menu.addAction(dashboard_action)
        menu.addAction(delegation_action)
        menu.addAction(history_action)
        menu.addAction(settings_action)

    def init_ui(self):
        self.stack = QStackedWidget()
        self.dashboard_page = DashboardPage()
        self.delegation_page = DelegationPage()
        self.history_page = HistoryPage()
        self.settings_page = SettingsPage()
        self.stack.addWidget(self.dashboard_page)
        self.stack.addWidget(self.delegation_page)
        self.stack.addWidget(self.history_page)
        self.stack.addWidget(self.settings_page)
        self.setCentralWidget(self.stack)

    def show_dashboard_page(self):
        self.stack.setCurrentWidget(self.dashboard_page)

    def show_delegation_page(self):
        self.stack.setCurrentWidget(self.delegation_page)

    def show_history_page(self):
        self.stack.setCurrentWidget(self.history_page)

    def show_settings_page(self):
        self.stack.setCurrentWidget(self.settings_page)


# gui/settings_page.py

from PyQt5.QtWidgets import QWidget, QLabel, QLineEdit, QPushButton, QVBoxLayout, QMessageBox, QFileDialog, QHBoxLayout
from PyQt5.QtGui import QPalette, QColor
from PyQt5.QtCore import Qt
import config.settings as settings
from database.db_manager import DBManager

class SettingsPage(QWidget):
    def __init__(self):
        super().__init__()
        self.db_manager = DBManager()
        self.init_ui()
        self.load_settings()

    def init_ui(self):
        # Aplicando o tema escuro
        self.setAutoFillBackground(True)
        palette = self.palette()
        palette.setColor(QPalette.Window, QColor(40, 40, 40))
        self.setPalette(palette)

        layout = QVBoxLayout()

        # Estilos
        label_style = "color: white; font-size: 14px;"
        input_style = """
            QLineEdit {
                background-color: #303030;
                color: white;
                padding: 5px;
                border: 1px solid #555555;
                border-radius: 3px;
            }
        """
        button_style = """
            QPushButton {
                background-color: #007ACC;
                color: white;
                font-size: 14px;
                padding: 6px 12px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #005999;
            }
        """

        # Campos de Configuração
        self.database_uri_label = QLabel('Database URI:')
        self.database_uri_label.setStyleSheet(label_style)
        self.database_uri_input = QLineEdit()
        self.database_uri_input.setStyleSheet(input_style)

        self.flask_host_label = QLabel('Flask Host:')
        self.flask_host_label.setStyleSheet(label_style)
        self.flask_host_input = QLineEdit()
        self.flask_host_input.setStyleSheet(input_style)

        self.flask_port_label = QLabel('Flask Port:')
        self.flask_port_label.setStyleSheet(label_style)
        self.flask_port_input = QLineEdit()
        self.flask_port_input.setStyleSheet(input_style)

        self.tron_node_url_label = QLabel('TRON Node URL:')
        self.tron_node_url_label.setStyleSheet(label_style)
        self.tron_node_url_input = QLineEdit()
        self.tron_node_url_input.setStyleSheet(input_style)

        self.private_key_label = QLabel('Chave Privada:')
        self.private_key_label.setStyleSheet(label_style)
        self.private_key_input = QLineEdit()
        self.private_key_input.setEchoMode(QLineEdit.Password)
        self.private_key_input.setStyleSheet(input_style)

        self.wallet_address_label = QLabel('Endereço da Carteira:')
        self.wallet_address_label.setStyleSheet(label_style)
        self.wallet_address_input = QLineEdit()
        self.wallet_address_input.setStyleSheet(input_style)

        self.min_balance_label = QLabel('Saldo Mínimo (TRX):')
        self.min_balance_label.setStyleSheet(label_style)
        self.min_balance_input = QLineEdit()
        self.min_balance_input.setStyleSheet(input_style)

        self.reinvest_threshold_label = QLabel('Limite de Reinvestimento (TRX):')
        self.reinvest_threshold_label.setStyleSheet(label_style)
        self.reinvest_threshold_input = QLineEdit()
        self.reinvest_threshold_input.setStyleSheet(input_style)

        # Botões de Salvar Configurações
        self.save_button = QPushButton('Salvar Configurações')
        self.save_button.setStyleSheet(button_style)
        self.save_button.clicked.connect(self.save_settings)

        # Botões de Exportação e Importação
        self.import_button = QPushButton('Importar Perfil')
        self.import_button.setStyleSheet(button_style)
        self.import_button.clicked.connect(self.import_profile)
        self.export_button = QPushButton('Exportar Perfil')
        self.export_button.setStyleSheet(button_style)
        self.export_button.clicked.connect(self.export_profile)

        # Layouts
        layout.addWidget(self.database_uri_label)
        layout.addWidget(self.database_uri_input)
        layout.addWidget(self.flask_host_label)
        layout.addWidget(self.flask_host_input)
        layout.addWidget(self.flask_port_label)
        layout.addWidget(self.flask_port_input)
        layout.addWidget(self.tron_node_url_label)
        layout.addWidget(self.tron_node_url_input)
        layout.addWidget(self.private_key_label)
        layout.addWidget(self.private_key_input)
        layout.addWidget(self.wallet_address_label)
        layout.addWidget(self.wallet_address_input)
        layout.addWidget(self.min_balance_label)
        layout.addWidget(self.min_balance_input)
        layout.addWidget(self.reinvest_threshold_label)
        layout.addWidget(self.reinvest_threshold_input)

        layout.addSpacing(20)

        button_layout = QHBoxLayout()
        button_layout.addWidget(self.save_button)
        button_layout.addWidget(self.import_button)
        button_layout.addWidget(self.export_button)
        layout.addLayout(button_layout)

        layout.addStretch()
        self.setLayout(layout)

    def load_settings(self):
        # Carrega as configurações existentes, se houver
        self.database_uri_input.setText(settings.DATABASE_URI or '')
        self.tron_node_url_input.setText(settings.TRON_NODE_URL or '')
        self.private_key_input.setText(settings.PRIVATE_KEY or '')
        self.wallet_address_input.setText(settings.WALLET_ADDRESS or '')
        self.min_balance_input.setText(str(settings.MINIMUM_BALANCE))
        self.reinvest_threshold_input.setText(str(settings.REINVEST_THRESHOLD))
        self.flask_host_input.setText(settings.FLASK_HOST or '')
        self.flask_port_input.setText(str(settings.FLASK_PORT))

    def save_settings(self):
        database_uri = self.database_uri_input.text()
        flask_host = self.flask_host_input.text()
        flask_port = self.flask_port_input.text()
        tron_node_url = self.tron_node_url_input.text()
        private_key = self.private_key_input.text()
        wallet_address = self.wallet_address_input.text()
        min_balance = self.min_balance_input.text()
        reinvest_threshold = self.reinvest_threshold_input.text()

        # Validar os campos obrigatórios
        if not database_uri:
            QMessageBox.warning(self, 'Erro', 'O Database URI não pode estar vazio.')
            return
        if not tron_node_url:
            QMessageBox.warning(self, 'Erro', 'O TRON Node URL não pode estar vazio.')
            return
        if not private_key:
            QMessageBox.warning(self, 'Erro', 'A chave privada não pode estar vazia.')
            return
        if not wallet_address:
            QMessageBox.warning(self, 'Erro', 'O endereço da carteira não pode estar vazio.')
            return
        if not flask_host:
            QMessageBox.warning(self, 'Erro', 'O Flask Host não pode estar vazio.')
            return
        if not flask_port:
            QMessageBox.warning(self, 'Erro', 'O Flask Port não pode estar vazio.')
            return

        # Validar os campos numéricos
        try:
            min_balance_value = float(min_balance)
            reinvest_threshold_value = float(reinvest_threshold)
        except ValueError:
            QMessageBox.warning(self, 'Erro', 'Os valores de saldo mínimo e limite de reinvestimento devem ser numéricos.')
            return

        try:
            flask_port_value = int(flask_port)
        except ValueError:
            QMessageBox.warning(self, 'Erro', 'O Flask Port deve ser um número inteiro.')
            return

        # Atualizar as configurações
        settings.update_settings(
            database_uri=database_uri,
            tron_node_url=tron_node_url,
            private_key=private_key,
            wallet_address=wallet_address,
            minimum_balance=min_balance_value,
            reinvest_threshold=reinvest_threshold_value,
            flask_host=flask_host,
            flask_port=flask_port_value
        )

        QMessageBox.information(self, 'Configurações Salvas', 'As configurações foram salvas com sucesso.')

    def import_profile(self):
        file_path, _ = QFileDialog.getOpenFileName(self, 'Importar Perfil', '', 'CSV Files (*.csv)')
        if file_path:
            try:
                self.db_manager.import_profile(file_path)
                QMessageBox.information(self, 'Perfil Importado', f'O perfil foi importado com sucesso de {file_path}.')
            except Exception as e:
                QMessageBox.warning(self, 'Erro', f'Erro ao importar perfil: {e}')

    def export_profile(self):
        file_path, _ = QFileDialog.getSaveFileName(self, 'Exportar Perfil', '', 'CSV Files (*.csv)')
        if file_path:
            try:
                self.db_manager.export_profile(file_path)
                QMessageBox.information(self, 'Perfil Exportado', f'O perfil foi exportado com sucesso para {file_path}.')
            except Exception as e:
                QMessageBox.warning(self, 'Erro', f'Erro ao exportar perfil: {e}')

def import_profile(self):
    file_path = QFileDialog.getExistingDirectory(self, 'Importar Perfil')
    if file_path:
        try:
            self.db_manager.import_profile(file_path)
            QMessageBox.information(self, 'Perfil Importado', f'O perfil foi importado com sucesso de {file_path}.')
        except Exception as e:
            QMessageBox.warning(self, 'Erro', f'Erro ao importar perfil: {e}')

def export_profile(self):
    dir_path = QFileDialog.getExistingDirectory(self, 'Exportar Perfil')
    if dir_path:
        try:
            self.db_manager.export_profile(dir_path)
            QMessageBox.information(self, 'Perfil Exportado', f'O perfil foi exportado com sucesso para {dir_path}.')
        except Exception as e:
            QMessageBox.warning(self, 'Erro', f'Erro ao exportar perfil: {e}')                

# utils/helpers.py

import requests

def select_best_sr():
    # Aqui, podemos implementar uma lógica mais avançada para selecionar o melhor SR
    # Por exemplo, consultar uma API que fornece as taxas de retorno dos SRs
    # Neste exemplo, simularemos a seleção
    return 'TJRyTQSWyrR845RX6D9yUSzLwevUppGoGM'  # Endereço de um SR de exemplo

def validate_wallet_address(address):
    # Implemente a validação do endereço da carteira TRON
    return True



# main.py

import sys
from PyQt5.QtWidgets import QApplication
from gui.main_window import MainWindow
from threading import Thread
from backend.flask_server import app
from automation.delegation_bot import DelegationBot
from config.settings import FLASK_HOST, FLASK_PORT

def start_flask():
    app.run(host=FLASK_HOST, port=FLASK_PORT)

def start_bot():
    bot = DelegationBot()
    bot.run()

if __name__ == '__main__':
    # Inicia o servidor Flask em uma thread separada
    flask_thread = Thread(target=start_flask)
    flask_thread.daemon = True
    flask_thread.start()

    # Inicia a interface gráfica
    app_gui = QApplication(sys.argv)
    window = MainWindow()
    window.show()

    # Iniciar o bot somente após a interface gráfica estar pronta
    bot_thread = Thread(target=start_bot)
    bot_thread.daemon = True
    bot_thread.start()

    sys.exit(app_gui.exec_())