import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np
from scipy.optimize import brentq
from datetime import datetime
import os

# ==============================================
# 1. CLASSE FLUXOCAIXAMANAGER (BACKEND)
# ==============================================

class FluxoCaixaManager:
    """Gerencia o carregamento, salvamento e manipulação dos dados de Entrada e Saída."""

    def __init__(self, data_path="."):
        self.path = data_path
        self.ENTRADAS_FILE = os.path.join(self.path, 'entradas.csv')
        self.SAIDAS_FILE = os.path.join(self.path, 'saidas.csv')
        
        # Estrutura de Colunas (Definida no Projeto)
        self.COLS_ENTRADAS = ['data', 'descricao', 'cliente', 'obra_projeto', 'categoria', 'valor']
        self.COLS_SAIDAS = ['data', 'descricao', 'obra_projeto', 'categoria', 'subcategoria', 
                           'fornecedor', 'valor', 'meio_pagamento']
        
        self.entradas_df = self._carregar_ou_criar(self.ENTRADAS_FILE, self.COLS_ENTRADAS)
        self.saidas_df = self._carregar_ou_criar(self.SAIDAS_FILE, self.COLS_SAIDAS)
        
        # Garante que a coluna 'data' esteja no formato correto
        self._limpar_e_formatar_data()

    def _limpar_e_formatar_data(self):
        """Converte as colunas de data para datetime e preenche NaN no valor com 0."""
        # Processa Entradas
        if not self.entradas_df.empty and 'data' in self.entradas_df.columns:
            self.entradas_df['data'] = pd.to_datetime(self.entradas_df['data'], errors='coerce', dayfirst=True)
        if not self.entradas_df.empty and 'valor' in self.entradas_df.columns:
            self.entradas_df['valor'] = pd.to_numeric(self.entradas_df['valor'], errors='coerce').fillna(0)
        
        # Processa Saídas
        if not self.saidas_df.empty and 'data' in self.saidas_df.columns:
            self.saidas_df['data'] = pd.to_datetime(self.saidas_df['data'], errors='coerce', dayfirst=True)
        if not self.saidas_df.empty and 'valor' in self.saidas_df.columns:
            self.saidas_df['valor'] = pd.to_numeric(self.saidas_df['valor'], errors='coerce').fillna(0)
        
    def _carregar_ou_criar(self, filename, columns):
        """Carrega CSV se existir, senão cria um DataFrame vazio."""
        if os.path.exists(filename):
            try:
                df = pd.read_csv(filename, encoding='utf-8', dayfirst=True)
                
                # Garante que o DF retornado tem apenas as colunas necessárias
                for col in columns:
                    if col not in df.columns:
                        df[col] = pd.NA
                        
                return df[columns]
            except Exception as e:
                print(f"ERRO ao carregar {filename}: {e}. Criando um novo DataFrame vazio.")
                return pd.DataFrame(columns=columns)
        else:
            return pd.DataFrame(columns=columns)

    def salvar_dados(self):
        """Salva ambos DataFrames de volta aos seus arquivos CSV."""
        try:
            # Salva mantendo o formato de data como string no padrão brasileiro
            if not self.entradas_df.empty:
                entradas_save = self.entradas_df.copy()
                if 'data' in entradas_save.columns:
                    entradas_save['data'] = entradas_save['data'].dt.strftime('%d/%m/%Y')
                entradas_save.to_csv(self.ENTRADAS_FILE, index=False, encoding='utf-8')
                
            if not self.saidas_df.empty:
                saidas_save = self.saidas_df.copy()
                if 'data' in saidas_save.columns:
                    saidas_save['data'] = saidas_save['data'].dt.strftime('%d/%m/%Y')
                saidas_save.to_csv(self.SAIDAS_FILE, index=False, encoding='utf-8')
                
            return True
        except Exception as e:
            print(f"ERRO ao salvar dados: {e}")
            return False

    def adicionar_entrada(self, **kwargs):
        """Adiciona uma nova linha de entrada (transação)."""
        try:
            # Converte data para datetime
            if 'data' in kwargs:
                kwargs['data'] = pd.to_datetime(kwargs['data'], errors='coerce', dayfirst=True)
            
            # Garante que valor é numérico
            if 'valor' in kwargs:
                kwargs['valor'] = float(kwargs['valor'])
            
            nova_linha = {col: kwargs.get(col, '') for col in self.COLS_ENTRADAS}
            self.entradas_df = pd.concat([self.entradas_df, pd.DataFrame([nova_linha])], ignore_index=True)
            self._limpar_e_formatar_data()  # Reformatar data após adição
            self.salvar_dados()
            return True
        except Exception as e:
            print(f"Erro ao adicionar entrada: {e}")
            return False
        
    def adicionar_saida(self, **kwargs):
        """Adiciona uma nova linha de saída (transação)."""
        try:
            # Converte data para datetime
            if 'data' in kwargs:
                kwargs['data'] = pd.to_datetime(kwargs['data'], errors='coerce', dayfirst=True)
            
            # Garante que valor é numérico
            if 'valor' in kwargs:
                kwargs['valor'] = float(kwargs['valor'])
            
            nova_linha = {col: kwargs.get(col, '') for col in self.COLS_SAIDAS}
            self.saidas_df = pd.concat([self.saidas_df, pd.DataFrame([nova_linha])], ignore_index=True)
            self._limpar_e_formatar_data()  # Reformatar data após adição
            self.salvar_dados()
            return True
        except Exception as e:
            print(f"Erro ao adicionar saída: {e}")
            return False

    # --- Funções de Relatório (Resumo Mensal para Gráfico Principal) ---
    
    def relatorio_saldo_mensal(self):
        """Retorna um DataFrame com Entradas, Saídas, Saldo Mensal e Saldo Acumulado."""
        try:
            # Cria cópias para evitar modificações nos dados originais
            df_ent = self.entradas_df.copy()
            df_sai = self.saidas_df.copy()
            
            # Verifica se há dados
            if df_ent.empty and df_sai.empty:
                return pd.DataFrame(columns=['Total Entradas', 'Total Saídas', 'Saldo Mensal', 'Saldo Acumulado'])
            
            # Garante formato datetime
            if 'data' in df_ent.columns:
                df_ent['data'] = pd.to_datetime(df_ent['data'], errors='coerce')
            if 'data' in df_sai.columns:
                df_sai['data'] = pd.to_datetime(df_sai['data'], errors='coerce')
            
            # 1. Agrupar por mês/ano
            if not df_ent.empty:
                entradas_mensais = df_ent.groupby(df_ent['data'].dt.to_period('M'))['valor'].sum().rename('Total Entradas')
            else:
                entradas_mensais = pd.Series([], name='Total Entradas')
                
            if not df_sai.empty:
                saidas_mensais = df_sai.groupby(df_sai['data'].dt.to_period('M'))['valor'].sum().rename('Total Saídas')
            else:
                saidas_mensais = pd.Series([], name='Total Saídas')
            
            # 2. Juntar os dados
            fluxo_mensal = pd.merge(entradas_mensais, saidas_mensais, 
                                   left_index=True, right_index=True, how='outer').fillna(0)
            
            # 3. Calcular Saldo
            fluxo_mensal['Saldo Mensal'] = fluxo_mensal['Total Entradas'] - fluxo_mensal['Total Saídas']
            fluxo_mensal['Saldo Acumulado'] = fluxo_mensal['Saldo Mensal'].cumsum()
            
            # 4. Formatar o índice para ser mais legível na GUI
            fluxo_mensal.index = fluxo_mensal.index.strftime('%Y-%m')
            
            return fluxo_mensal.sort_index()
            
        except Exception as e:
            print(f"Erro ao gerar relatório mensal: {e}")
            return pd.DataFrame(columns=['Total Entradas', 'Total Saídas', 'Saldo Mensal', 'Saldo Acumulado'])

    def relatorio_custos_por_obra(self, obra=None):
        """Filtra as despesas pela coluna 'obra_projeto' e as categoriza."""
        df = self.saidas_df.copy()
        
        if df.empty:
            return pd.Series([], name='Valor')
            
        if obra and obra != "Todas":
            df = df[df['obra_projeto'] == obra]
        
        # Agrupa por Categoria e soma o valor
        if 'categoria' in df.columns and 'valor' in df.columns:
            relatorio = df.groupby('categoria')['valor'].sum().sort_values(ascending=False)
            return relatorio
        else:
            return pd.Series([], name='Valor')
    
    def relatorio_detalhado_entradas(self):
        """Retorna DataFrame com todas as entradas detalhadas."""
        return self.entradas_df.copy()
    
    def relatorio_detalhado_saidas(self):
        """Retorna DataFrame com todas as saídas detalhadas."""
        return self.saidas_df.copy()
    
    def excluir_transacao(self, tipo, index):
        """Exclui uma transação específica."""
        try:
            if tipo == 'entrada':
                if index < len(self.entradas_df):
                    self.entradas_df = self.entradas_df.drop(index).reset_index(drop=True)
                    self.salvar_dados()
                    return True
            elif tipo == 'saida':
                if index < len(self.saidas_df):
                    self.saidas_df = self.saidas_df.drop(index).reset_index(drop=True)
                    self.salvar_dados()
                    return True
            return False
        except Exception as e:
            print(f"Erro ao excluir transação: {e}")
            return False

# ==============================================
# 2. CLASSE PRINCIPAL (FRONTEND) - COM ANÁLISE DE SENSIBILIDADE
# ==============================================

class FluxoCaixaApp:
    def __init__(self, root):
        self.root = root
        self.root.title("🏗️ Gestão de Fluxo de Caixa - Construtora")
        self.root.geometry("1400x900")
        self.root.minsize(1200, 700)
        
        # Estilo
        style = ttk.Style()
        style.theme_use('clam')
        style.configure('Title.TLabel', font=('Arial', 16, 'bold'))
        style.configure('Header.TLabel', font=('Arial', 12, 'bold'))
        style.configure('Accent.TButton', background='#28a745')
        style.map('Accent.TButton', background=[('active', '#218838')])
        
        # 🛑 MUDANÇA PRINCIPAL: Instanciar o Manager
        self.manager = FluxoCaixaManager()
        
        # Definição das categorias pré-definidas
        self.CATEGORIAS_ENTRADA = [
            "Medição de Obra", 
            "Venda de Imóvel", 
            "Serviços Extras",
            "Empréstimo/Financiamento", 
            "Capital Social", 
            "Venda de Ativos",
            "Outros / Customizável"
        ]
        
        self.CATEGORIAS_SAIDA = [
            "Mão de Obra", 
            "Materiais", 
            "Equipamentos", 
            "Administrativo", 
            "Impostos e Taxas", 
            "Serviços", 
            "Marketing e Vendas", 
            "Financeiro", 
            "Outros / Customizável"
        ]
        
        self.SUBCATEGORIAS_SAIDA = {
            "Mão de Obra": ["Salários", "Encargos Sociais", "Benefícios", "Horas Extras", "Serviços Terceirizados"],
            "Materiais": ["Estrutura", "Alvenaria", "Elétrica", "Hidráulica", "Acabamento", "Esquadrias", "Paisagismo"],
            "Equipamentos": ["Aluguel de Máquinas", "Manutenção de Frota", "Combustível", "Compra de Ferramentas"],
            "Administrativo": ["Aluguel de Escritório", "Contabilidade", "Software de Gestão", "Material de Escritório"],
            "Impostos e Taxas": ["ISS", "IPTU", "Taxa de Alvará", "Licenças", "Impostos sobre Folha"],
            "Serviços": ["Projetos Arquitetônico", "Projetos Estrutural", "Topografia", "Inspeção/Laudos", "Consultoria"],
            "Marketing e Vendas": ["Publicidade", "Comissão de Vendas", "Feiras e Eventos"],
            "Financeiro": ["Juros Bancários", "Encargos Bancários", "Tarifas de TED/DOC"],
            "Outros / Customizável": ["Diversos", "Não Classificados"]
        }
        
        self.MEIO_PAGAMENTO = ["Dinheiro", "PIX", "Transferência", "Cartão de Crédito", "Cartão de Débito", "Cheque", "Boleto"]
        
        # Dados para exibição (agregados mensais)
        self.dados_relatorio = pd.DataFrame()
        self.tipo_transacao = "entrada"  # Padrão para entrada
        self.setup_ui()
        
        # Carrega dados iniciais
        self.atualizar_dados_relatorio()
        self.atualizar_tabela_agregada()
        self.mostrar_analise_completa()
        
        # 🛑 MUDANÇA: Salvamento automático ao fechar
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)

    def on_closing(self):
        """Função chamada ao fechar a janela para salvar dados."""
        if self.manager.salvar_dados():
            print("Dados salvos automaticamente ao fechar.")
        else:
            messagebox.showerror("Erro", "Falha ao salvar os dados.")
        self.root.destroy()
    
    def setup_ui(self):
        # Toolbar
        self.setup_toolbar()
        
        # Notebook principal
        notebook = ttk.Notebook(self.root)
        notebook.pack(fill='both', expand=True, padx=10, pady=10)

        # Aba 1: Entrada de Dados (Transações Detalhadas)
        self.frame_entrada = ttk.Frame(notebook)
        notebook.add(self.frame_entrada, text="📝 Nova Transação")
        self.setup_entrada_frame()

        # Aba 2: Tabela Agregada (Resumo Mensal)
        self.frame_tabela = ttk.Frame(notebook)
        notebook.add(self.frame_tabela, text="📊 Resumo Mensal")
        self.setup_tabela_frame()

        # Aba 3: Transações Detalhadas
        self.frame_detalhes = ttk.Frame(notebook)
        notebook.add(self.frame_detalhes, text="📋 Transações Detalhadas")
        self.setup_detalhes_frame()

        # Aba 4: Gráficos
        self.frame_grafico = ttk.Frame(notebook)
        notebook.add(self.frame_grafico, text="📈 Gráficos")
        self.setup_grafico_frame()

        # Aba 5: Análise
        self.frame_analise = ttk.Frame(notebook)
        notebook.add(self.frame_analise, text="💹 Análise Financeira")
        self.setup_analise_frame()

    def setup_toolbar(self):
        toolbar = ttk.Frame(self.root)
        toolbar.pack(fill='x', padx=10, pady=5)
        
        # Botão para alternar entre Entrada/Saída
        self.btn_tipo = ttk.Button(toolbar, text="📥 Entrada", command=self.alternar_tipo_transacao)
        self.btn_tipo.pack(side='left', padx=2)
        
        ttk.Button(toolbar, text="💾 Salvar", command=self.salvar_dados).pack(side='left', padx=2)
        ttk.Button(toolbar, text="🔄 Atualizar", command=self.atualizar_tudo).pack(side='left', padx=2)
        ttk.Button(toolbar, text="📊 Relatório Obra", command=self.mostrar_relatorio_obra).pack(side='left', padx=2)
        ttk.Button(toolbar, text="📤 Exportar CSV", command=self.exportar_dados).pack(side='left', padx=2)
        ttk.Button(toolbar, text="📈 Análise de Sensibilidade", command=self.mostrar_analise_sensibilidade).pack(side='left', padx=2)
        ttk.Button(toolbar, text="🗑️ Limpar Tudo", command=self.limpar_tudo).pack(side='right', padx=2)

    def setup_entrada_frame(self):
        # Título dinâmico baseado no tipo
        self.label_titulo = ttk.Label(self.frame_entrada, text="Nova Entrada", style='Title.TLabel')
        self.label_titulo.pack(pady=10)
        
        # Frame principal com scroll
        main_frame = ttk.Frame(self.frame_entrada)
        main_frame.pack(fill='both', expand=True, padx=20)
        
        # Grid de entradas
        self.entries = {}
        row = 0
        
        # Campos comuns
        ttk.Label(main_frame, text="📅 Data (DD/MM/AAAA) *", style='Header.TLabel').grid(row=row, column=0, sticky='w', pady=5)
        self.entry_data = ttk.Entry(main_frame, font=('Arial', 10))
        self.entry_data.insert(0, datetime.now().strftime("%d/%m/%Y"))
        self.entry_data.grid(row=row, column=1, sticky='ew', pady=5)
        self.entries['data'] = self.entry_data
        row += 1
        
        ttk.Label(main_frame, text="📋 Descrição *", style='Header.TLabel').grid(row=row, column=0, sticky='w', pady=5)
        self.entry_descricao = ttk.Entry(main_frame, font=('Arial', 10))
        self.entry_descricao.grid(row=row, column=1, sticky='ew', pady=5)
        self.entries['descricao'] = self.entry_descricao
        row += 1
        
        ttk.Label(main_frame, text="🏗️ Obra/Projeto *", style='Header.TLabel').grid(row=row, column=0, sticky='w', pady=5)
        self.entry_obra = ttk.Entry(main_frame, font=('Arial', 10))
        self.entry_obra.grid(row=row, column=1, sticky='ew', pady=5)
        self.entries['obra_projeto'] = self.entry_obra
        row += 1
        
        ttk.Label(main_frame, text="🏷️ Categoria *", style='Header.TLabel').grid(row=row, column=0, sticky='w', pady=5)
        self.combo_categoria = ttk.Combobox(main_frame, values=self.CATEGORIAS_ENTRADA, font=('Arial', 10), state="readonly")
        self.combo_categoria.set(self.CATEGORIAS_ENTRADA[0])  # Define valor padrão
        self.combo_categoria.grid(row=row, column=1, sticky='ew', pady=5)
        self.entries['categoria'] = self.combo_categoria
        row += 1
        
        ttk.Label(main_frame, text="💰 Valor (R$) *", style='Header.TLabel').grid(row=row, column=0, sticky='w', pady=5)
        self.entry_valor = ttk.Entry(main_frame, font=('Arial', 10))
        self.entry_valor.grid(row=row, column=1, sticky='ew', pady=5)
        self.entries['valor'] = self.entry_valor
        row += 1
        
        # Campos específicos para Entrada
        self.label_cliente = ttk.Label(main_frame, text="👤 Cliente *", style='Header.TLabel')
        self.entry_cliente = ttk.Entry(main_frame, font=('Arial', 10))
        
        # Campos específicos para Saída
        self.label_subcategoria = ttk.Label(main_frame, text="📂 Subcategoria", style='Header.TLabel')
        self.combo_subcategoria = ttk.Combobox(main_frame, font=('Arial', 10), state="readonly")
        
        self.label_fornecedor = ttk.Label(main_frame, text="🏢 Fornecedor", style='Header.TLabel')
        self.entry_fornecedor = ttk.Entry(main_frame, font=('Arial', 10))
        
        self.label_meio_pagamento = ttk.Label(main_frame, text="💳 Meio de Pagamento", style='Header.TLabel')
        self.combo_meio_pagamento = ttk.Combobox(main_frame, values=self.MEIO_PAGAMENTO, font=('Arial', 10), state="readonly")
        self.combo_meio_pagamento.set(self.MEIO_PAGAMENTO[0])  # Define valor padrão
        
        # Posiciona os campos de entrada (CLIENTE) - Configuração inicial
        self.label_cliente.grid(row=row, column=0, sticky='w', pady=5)
        self.entry_cliente.grid(row=row, column=1, sticky='ew', pady=5)
        self.entries['cliente'] = self.entry_cliente
        
        # Configurar pesos
        main_frame.grid_columnconfigure(1, weight=1)
        
        # Botões
        btn_frame = ttk.Frame(main_frame)
        btn_frame.grid(row=row+1, column=0, columnspan=2, pady=20)
        
        ttk.Button(btn_frame, text="💾 SALVAR TRANSAÇÃO", command=self.salvar_transacao, 
                  style='Accent.TButton').pack(side='left', padx=10)
        ttk.Button(btn_frame, text="🧹 LIMPAR", command=self.limpar_campos).pack(side='left', padx=10)
        ttk.Button(btn_frame, text="❓ AJUDA", command=self.mostrar_ajuda).pack(side='left', padx=10)

    def setup_tabela_frame(self):
        # Treeview para dados agregados
        columns = ("Mês", "Total Entradas", "Total Saídas", "Saldo Mensal", "Saldo Acumulado")
        
        self.tree_agregado = ttk.Treeview(self.frame_tabela, columns=columns, show='headings', height=20)
        
        # Configurar colunas
        col_widths = [100, 120, 120, 120, 120]
        for i, col in enumerate(columns):
            self.tree_agregado.heading(col, text=col)
            self.tree_agregado.column(col, width=col_widths[i], anchor='e')
            if col == "Mês":
                self.tree_agregado.column(col, anchor='w')
        
        # Scrollbar
        scrollbar = ttk.Scrollbar(self.frame_tabela, orient="vertical", command=self.tree_agregado.yview)
        self.tree_agregado.configure(yscrollcommand=scrollbar.set)
        
        self.tree_agregado.pack(side='left', fill='both', expand=True, padx=10, pady=10)
        scrollbar.pack(side='right', fill='y')
        
        # Frame de resumo
        resumo_frame = ttk.Frame(self.frame_tabela)
        resumo_frame.pack(fill='x', padx=10, pady=5)
        
        self.label_resumo = ttk.Label(resumo_frame, text="", font=('Arial', 12, 'bold'))
        self.label_resumo.pack()

    def setup_detalhes_frame(self):
        notebook_detalhes = ttk.Notebook(self.frame_detalhes)
        notebook_detalhes.pack(fill='both', expand=True, padx=10, pady=10)
        
        # Aba de Entradas
        frame_entradas = ttk.Frame(notebook_detalhes)
        notebook_detalhes.add(frame_entradas, text="📥 Entradas")
        self.setup_tabela_detalhada(frame_entradas, "entrada")
        
        # Aba de Saídas
        frame_saidas = ttk.Frame(notebook_detalhes)
        notebook_detalhes.add(frame_saidas, text="📤 Saídas")
        self.setup_tabela_detalhada(frame_saidas, "saida")

    def setup_tabela_detalhada(self, parent, tipo):
        # Configura colunas baseadas no tipo
        if tipo == "entrada":
            columns = ("ID", "Data", "Descrição", "Cliente", "Obra", "Categoria", "Valor", "Ações")
        else:
            columns = ("ID", "Data", "Descrição", "Obra", "Categoria", "Subcategoria", "Fornecedor", "Valor", "Pagamento", "Ações")
        
        # Frame principal
        main_frame = ttk.Frame(parent)
        main_frame.pack(fill='both', expand=True)
        
        # Treeview
        tree = ttk.Treeview(main_frame, columns=columns, show='headings', height=15)
        
        # Configurar colunas
        col_widths = {"ID": 40, "Data": 80, "Descrição": 150, "Cliente": 100, "Obra": 120, 
                     "Categoria": 120, "Subcategoria": 120, "Fornecedor": 120, "Valor": 100, 
                     "Pagamento": 100, "Ações": 60}
        
        for col in columns:
            tree.heading(col, text=col)
            width = col_widths.get(col, 100)
            tree.column(col, width=width, anchor='center')
            if col in ["Descrição", "Cliente", "Fornecedor"]:
                tree.column(col, anchor='w')
            if col == "Valor":
                tree.column(col, anchor='e')
        
        # Scrollbar vertical
        v_scrollbar = ttk.Scrollbar(main_frame, orient="vertical", command=tree.yview)
        tree.configure(yscrollcommand=v_scrollbar.set)
        
        # Scrollbar horizontal
        h_scrollbar = ttk.Scrollbar(main_frame, orient="horizontal", command=tree.xview)
        tree.configure(xscrollcommand=h_scrollbar.set)
        
        # Posicionamento
        tree.grid(row=0, column=0, sticky='nsew')
        v_scrollbar.grid(row=0, column=1, sticky='ns')
        h_scrollbar.grid(row=1, column=0, sticky='ew', columnspan=2)
        
        main_frame.grid_rowconfigure(0, weight=1)
        main_frame.grid_columnconfigure(0, weight=1)
        
        # Bind para exclusão
        tree.bind('<Double-1>', lambda e, t=tipo: self.excluir_transacao_detalhada(e, t))
        
        # Armazenar referência
        if tipo == "entrada":
            self.tree_entradas = tree
        else:
            self.tree_saidas = tree

    def setup_grafico_frame(self):
        ttk.Label(self.frame_grafico, text="📈 Evolução do Fluxo de Caixa", 
                 style='Title.TLabel').pack(pady=10)
        
        # Frame para controles do gráfico
        controle_frame = ttk.Frame(self.frame_grafico)
        controle_frame.pack(fill='x', padx=20, pady=5)
        
        ttk.Button(controle_frame, text="🔄 Atualizar Gráfico", 
                  command=self.plotar_grafico).pack(side='left', padx=5)
        ttk.Button(controle_frame, text="💾 Exportar Imagem", 
                  command=self.exportar_grafico).pack(side='left', padx=5)
        
        self.canvas_frame = ttk.Frame(self.frame_grafico)
        self.canvas_frame.pack(fill='both', expand=True, padx=20, pady=10)

    def setup_analise_frame(self):
        ttk.Label(self.frame_analise, text="💹 Análise Financeira e Viabilidade", 
                 style='Title.TLabel').pack(pady=10)
        
        # Frame para parâmetros de análise
        param_frame = ttk.Frame(self.frame_analise)
        param_frame.pack(fill='x', padx=20, pady=10)
        
        ttk.Label(param_frame, text="💎 Investimento Inicial (R$):").pack(side='left', padx=5)
        self.entry_invest_inicial = ttk.Entry(param_frame, width=15)
        self.entry_invest_inicial.insert(0, "-10000")
        self.entry_invest_inicial.pack(side='left', padx=5)
        
        ttk.Label(param_frame, text="📊 TMA (% a.a.):").pack(side='left', padx=5)
        self.entry_tma = ttk.Entry(param_frame, width=10)
        self.entry_tma.insert(0, "12")
        self.entry_tma.pack(side='left', padx=5)
        
        ttk.Button(param_frame, text="🔄 Calcular", command=self.mostrar_analise_completa).pack(side='left', padx=20)
        
        self.text_analise = tk.Text(self.frame_analise, wrap='word', font=('Consolas', 11),
                                   height=20, bg='#f8f9fa')
        self.text_analise.pack(fill='both', expand=True, padx=20, pady=10)

    def alternar_tipo_transacao(self):
        """Alterna entre entrada e saída."""
        current_row = 5  # Linha após os campos comuns
        
        if self.tipo_transacao == "entrada":
            self.tipo_transacao = "saida"
            self.btn_tipo.config(text="📤 Saída")
            self.label_titulo.config(text="Nova Saída")
            
            # Esconde campos de entrada
            self.label_cliente.grid_forget()
            self.entry_cliente.grid_forget()
            
            # Atualiza combobox de categoria
            self.combo_categoria['values'] = self.CATEGORIAS_SAIDA
            self.combo_categoria.set(self.CATEGORIAS_SAIDA[0])
            
            # Mostra campos de saída
            self.label_subcategoria.grid(row=current_row, column=0, sticky='w', pady=5)
            self.combo_subcategoria.grid(row=current_row, column=1, sticky='ew', pady=5)
            self.entries['subcategoria'] = self.combo_subcategoria
            current_row += 1
            
            self.label_fornecedor.grid(row=current_row, column=0, sticky='w', pady=5)
            self.entry_fornecedor.grid(row=current_row, column=1, sticky='ew', pady=5)
            self.entries['fornecedor'] = self.entry_fornecedor
            current_row += 1
            
            self.label_meio_pagamento.grid(row=current_row, column=0, sticky='w', pady=5)
            self.combo_meio_pagamento.grid(row=current_row, column=1, sticky='ew', pady=5)
            self.entries['meio_pagamento'] = self.combo_meio_pagamento
            
            # Atualiza subcategorias quando categoria muda
            self.combo_categoria.bind('<<ComboboxSelected>>', self.atualizar_subcategorias)
            self.atualizar_subcategorias()
            
        else:
            self.tipo_transacao = "entrada"
            self.btn_tipo.config(text="📥 Entrada")
            self.label_titulo.config(text="Nova Entrada")
            
            # Esconde campos de saída
            self.label_subcategoria.grid_forget()
            self.combo_subcategoria.grid_forget()
            self.label_fornecedor.grid_forget()
            self.entry_fornecedor.grid_forget()
            self.label_meio_pagamento.grid_forget()
            self.combo_meio_pagamento.grid_forget()
            
            # Remove dos entries
            if 'subcategoria' in self.entries:
                del self.entries['subcategoria']
            if 'fornecedor' in self.entries:
                del self.entries['fornecedor']
            if 'meio_pagamento' in self.entries:
                del self.entries['meio_pagamento']
            
            # Atualiza combobox de categoria
            self.combo_categoria['values'] = self.CATEGORIAS_ENTRADA
            self.combo_categoria.set(self.CATEGORIAS_ENTRADA[0])
            
            # Remove binding
            self.combo_categoria.unbind('<<ComboboxSelected>>')
            
            # Mostra campos de entrada
            self.label_cliente.grid(row=current_row, column=0, sticky='w', pady=5)
            self.entry_cliente.grid(row=current_row, column=1, sticky='ew', pady=5)
            self.entries['cliente'] = self.entry_cliente

    def atualizar_subcategorias(self, event=None):
        """Atualiza as subcategorias baseadas na categoria selecionada."""
        categoria = self.combo_categoria.get()
        if categoria in self.SUBCATEGORIAS_SAIDA:
            self.combo_subcategoria['values'] = self.SUBCATEGORIAS_SAIDA[categoria]
            if self.SUBCATEGORIAS_SAIDA[categoria]:
                self.combo_subcategoria.set(self.SUBCATEGORIAS_SAIDA[categoria][0])
        else:
            self.combo_subcategoria['values'] = []
            self.combo_subcategoria.set('')

    def salvar_transacao(self):
        """Salva uma nova transação detalhada."""
        try:
            # Validação básica
            data = self.entry_data.get().strip()
            descricao = self.entry_descricao.get().strip()
            obra = self.entry_obra.get().strip()
            valor_str = self.entry_valor.get().strip()
            categoria = self.combo_categoria.get().strip()
            
            # Validações específicas por tipo
            if self.tipo_transacao == "entrada":
                cliente = self.entry_cliente.get().strip()
                if not cliente:
                    messagebox.showerror("Erro", "Preencha o campo Cliente!")
                    self.entry_cliente.focus()
                    return
            else:
                fornecedor = self.entry_fornecedor.get().strip()
                if not fornecedor:
                    messagebox.showerror("Erro", "Preencha o campo Fornecedor!")
                    self.entry_fornecedor.focus()
                    return
            
            if not data or not descricao or not obra or not valor_str or not categoria:
                messagebox.showerror("Erro", "Preencha todos os campos obrigatórios (*)!")
                return
            
            # Valida formato da data
            try:
                datetime.strptime(data, "%d/%m/%Y")
            except ValueError:
                messagebox.showerror("Erro", "Data inválida! Use o formato DD/MM/AAAA")
                self.entry_data.focus()
                return
            
            # Converte valor para float
            try:
                valor = float(valor_str.replace(',', '.'))
                if valor <= 0:
                    messagebox.showerror("Erro", "Valor deve ser maior que zero!")
                    self.entry_valor.focus()
                    return
            except ValueError:
                messagebox.showerror("Erro", "Valor deve ser um número válido!")
                self.entry_valor.focus()
                return
            
            # Prepara os dados
            kwargs = {
                'data': data,
                'descricao': descricao,
                'obra_projeto': obra,
                'categoria': categoria,
                'valor': valor
            }
            
            # Adiciona campos específicos
            if self.tipo_transacao == "entrada":
                kwargs['cliente'] = self.entry_cliente.get().strip()
            else:
                kwargs['subcategoria'] = self.combo_subcategoria.get().strip()
                kwargs['fornecedor'] = self.entry_fornecedor.get().strip()
                kwargs['meio_pagamento'] = self.combo_meio_pagamento.get().strip()
            
            # Salva no manager apropriado
            if self.tipo_transacao == "entrada":
                success = self.manager.adicionar_entrada(**kwargs)
                msg_type = "Entrada"
            else:
                success = self.manager.adicionar_saida(**kwargs)
                msg_type = "Saída"
            
            if success:
                messagebox.showinfo("✅ Sucesso", f"{msg_type} registrada com sucesso!")
                self.limpar_campos()
                self.atualizar_tudo()
            else:
                messagebox.showerror("Erro", f"Falha ao salvar {msg_type.lower()}!")
                
        except Exception as e:
            messagebox.showerror("❌ Erro", f"Erro ao salvar: {str(e)}")

    def atualizar_dados_relatorio(self):
        """Atualiza os dados agregados do relatório."""
        self.dados_relatorio = self.manager.relatorio_saldo_mensal()

    def atualizar_tabela_agregada(self):
        """Atualiza a tabela com dados agregados mensais."""
        # Limpa a tabela
        for item in self.tree_agregado.get_children():
            self.tree_agregado.delete(item)
        
        # Preenche com novos dados
        if not self.dados_relatorio.empty:
            for idx, row in self.dados_relatorio.iterrows():
                self.tree_agregado.insert("", "end", values=(
                    idx,
                    f"R$ {row['Total Entradas']:,.2f}",
                    f"R$ {row['Total Saídas']:,.2f}",
                    f"R$ {row['Saldo Mensal']:,.2f}",
                    f"R$ {row['Saldo Acumulado']:,.2f}"
                ))
            
            # Atualiza resumo
            total_entradas = self.dados_relatorio['Total Entradas'].sum()
            total_saidas = self.dados_relatorio['Total Saídas'].sum()
            saldo_final = self.dados_relatorio['Saldo Acumulado'].iloc[-1] if len(self.dados_relatorio) > 0 else 0
            
            cor = 'green' if saldo_final >= 0 else 'red'
            self.label_resumo.config(
                text=f"💰 Total Entradas: R$ {total_entradas:,.2f} | "
                     f"Total Saídas: R$ {total_saidas:,.2f} | "
                     f"Saldo Final: R$ {saldo_final:,.2f}",
                foreground=cor
            )
        else:
            self.label_resumo.config(text="⚠️ Nenhum dado disponível")
        
        # Atualiza tabelas detalhadas
        self.atualizar_tabelas_detalhadas()

    def atualizar_tabelas_detalhadas(self):
        """Atualiza as tabelas de transações detalhadas."""
        # Entradas
        for item in self.tree_entradas.get_children():
            self.tree_entradas.delete(item)
        
        entradas_df = self.manager.relatorio_detalhado_entradas()
        if not entradas_df.empty:
            for idx, row in entradas_df.iterrows():
                data_str = row['data'].strftime('%d/%m/%Y') if pd.notna(row['data']) else ''
                self.tree_entradas.insert("", "end", values=(
                    idx,
                    data_str,
                    str(row.get('descricao', '')),
                    str(row.get('cliente', '')),
                    str(row.get('obra_projeto', '')),
                    str(row.get('categoria', '')),
                    f"R$ {float(row.get('valor', 0)):,.2f}",
                    "❌ Excluir"
                ))
        
        # Saídas
        for item in self.tree_saidas.get_children():
            self.tree_saidas.delete(item)
        
        saidas_df = self.manager.relatorio_detalhado_saidas()
        if not saidas_df.empty:
            for idx, row in saidas_df.iterrows():
                data_str = row['data'].strftime('%d/%m/%Y') if pd.notna(row['data']) else ''
                self.tree_saidas.insert("", "end", values=(
                    idx,
                    data_str,
                    str(row.get('descricao', '')),
                    str(row.get('obra_projeto', '')),
                    str(row.get('categoria', '')),
                    str(row.get('subcategoria', '')),
                    str(row.get('fornecedor', '')),
                    f"R$ {float(row.get('valor', 0)):,.2f}",
                    str(row.get('meio_pagamento', '')),
                    "❌ Excluir"
                ))

    def excluir_transacao_detalhada(self, event, tipo):
        """Exclui uma transação detalhada."""
        # Identifica qual tree foi clicada
        if tipo == "entrada":
            tree = self.tree_entradas
            tipo_str = "entrada"
        else:
            tree = self.tree_saidas
            tipo_str = "saída"
        
        # Obtém o item selecionado
        selection = tree.selection()
        if not selection:
            return
        
        item = selection[0]
        values = tree.item(item, 'values')
        
        if not values or len(values) < 8:
            return
        
        # O ID está na primeira coluna
        try:
            index = int(values[0])
        except (ValueError, IndexError):
            return
        
        # Confirmação
        descricao = values[2] if len(values) > 2 else ""
        valor = values[6] if len(values) > 6 else ""
        if messagebox.askyesno("Confirmar", f"Excluir {tipo_str}:\n{descricao}\nValor: {valor}?"):
            if self.manager.excluir_transacao(tipo_str, index):
                messagebox.showinfo("✅ Sucesso", f"{tipo_str.capitalize()} excluída!")
                self.atualizar_tudo()
            else:
                messagebox.showerror("Erro", f"Falha ao excluir {tipo_str}!")

    def plotar_grafico(self):
        """Plota o gráfico de evolução do fluxo de caixa."""
        for widget in self.canvas_frame.winfo_children():
            widget.destroy()

        if self.dados_relatorio.empty:
            ttk.Label(self.canvas_frame, text="⚠️ Nenhum dado disponível para gráfico", 
                     font=('Arial', 12)).pack(expand=True)
            return

        fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10), facecolor='white')
        meses = self.dados_relatorio.index
        
        # Gráfico 1: Saldo Acumulado
        ax1.plot(meses, self.dados_relatorio['Saldo Acumulado'], marker='o', linewidth=2, 
                label='Saldo Acumulado', color='#2E8B57')
        ax1.fill_between(meses, self.dados_relatorio['Saldo Acumulado'], alpha=0.3, color='#2E8B57')
        ax1.set_title('📈 Evolução do Saldo Acumulado', fontsize=14, fontweight='bold', pad=10)
        ax1.set_ylabel('Saldo Acumulado (R$)', fontsize=11, color='#2E8B57')
        ax1.tick_params(axis='y', labelcolor='#2E8B57')
        ax1.grid(True, alpha=0.3)
        ax1.legend(loc='upper left')
        ax1.set_xticks(range(len(meses)))
        ax1.set_xticklabels(meses, rotation=45, ha='right')
        
        # Formatação de valores
        ax1.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'R$ {x:,.0f}'))
        
        # Gráfico 2: Entradas vs Saídas
        width = 0.35
        x = np.arange(len(meses))
        
        ax2.bar(x - width/2, self.dados_relatorio['Total Entradas'], width=width, 
                alpha=0.7, label='Entradas', color='#32CD32', edgecolor='black')
        ax2.bar(x + width/2, self.dados_relatorio['Total Saídas'], width=width, 
                alpha=0.7, label='Saídas', color='#FF6347', edgecolor='black')
        
        ax2.set_title('📊 Entradas vs Saídas Mensais', fontsize=14, fontweight='bold', pad=10)
        ax2.set_xlabel('Mês', fontsize=11)
        ax2.set_ylabel('Valor (R$)', fontsize=11)
        ax2.set_xticks(x)
        ax2.set_xticklabels(meses, rotation=45, ha='right')
        ax2.grid(True, alpha=0.3, axis='y')
        ax2.legend(loc='upper left')
        
        # Formatação de valores
        ax2.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'R$ {x:,.0f}'))
        
        plt.tight_layout()

        canvas = FigureCanvasTkAgg(fig, master=self.canvas_frame)
        canvas.draw()
        canvas.get_tk_widget().pack(fill='both', expand=True)

    def calcular_indicadores(self, invest_inicial, tma_pct):
        """Calcula todos os indicadores financeiros."""
        if self.dados_relatorio.empty:
            return None
            
        try:
            # Prepara fluxos para análise
            fluxos_mensais = self.dados_relatorio['Saldo Mensal'].tolist()
            net_fluxos = [invest_inicial] + fluxos_mensais

            # Cálculos básicos
            vpl = self.calculate_npv(tma_pct, net_fluxos)
            tir = self.calculate_irr(net_fluxos)
            
            # Payback
            cumulative = np.cumsum(net_fluxos)
            payback = next((i for i, val in enumerate(cumulative) if val >= 0), None)
            payback_str = f"{payback} meses" if payback is not None else "Não recupera"

            # VPLA
            n = len(net_fluxos) - 1
            if n > 0 and tma_pct != 0:
                annuity_factor = (1 - (1 + tma_pct) ** -n) / tma_pct
                vpla = vpl / annuity_factor
            else:
                vpla = 0

            return {
                'vpl': vpl,
                'tir': tir,
                'payback': payback,
                'payback_str': payback_str,
                'vpla': vpla,
                'net_fluxos': net_fluxos
            }
        except Exception as e:
            print(f"Erro ao calcular indicadores: {e}")
            return None

    def analisar_sensibilidade(self, rate, net_fluxos):
        """Calcula VPLs para cenários de TMA mais alta e mais baixa."""
        # TMA 10% abaixo do padrão (cenário otimista)
        rate_otimista = max(0.01, rate * 0.90)
        vpl_otimista = self.calculate_npv(rate_otimista, net_fluxos)

        # TMA 10% acima do padrão (cenário pessimista)
        rate_pessimista = rate * 1.10
        vpl_pessimista = self.calculate_npv(rate_pessimista, net_fluxos)
        
        # TMA 20% acima do padrão (cenário crítico)
        rate_critico = rate * 1.20
        vpl_critico = self.calculate_npv(rate_critico, net_fluxos)
        
        return {
            'vpl_otimista': vpl_otimista,
            'rate_otimista': rate_otimista,
            'vpl_pessimista': vpl_pessimista,
            'rate_pessimista': rate_pessimista,
            'vpl_critico': vpl_critico,
            'rate_critico': rate_critico
        }

    def calcular_analise_cenarios(self, invest_inicial):
        """Calcula análise para diferentes cenários de investimento."""
        if self.dados_relatorio.empty:
            return None
            
        try:
            # Cenários de investimento
            cenarios = {
                'Baixo': invest_inicial * 0.8,   # 20% menor
                'Médio': invest_inicial,         # Original
                'Alto': invest_inicial * 1.2     # 20% maior
            }
            
            resultados = {}
            fluxos_mensais = self.dados_relatorio['Saldo Mensal'].tolist()
            tma_padrao = float(self.entry_tma.get() or 12) / 100
            
            for nome, invest in cenarios.items():
                net_fluxos = [invest] + fluxos_mensais
                vpl = self.calculate_npv(tma_padrao, net_fluxos)
                tir = self.calculate_irr(net_fluxos)
                
                resultados[nome] = {
                    'investimento': invest,
                    'vpl': vpl,
                    'tir': tir * 100
                }
            
            return resultados
        except Exception as e:
            print(f"Erro ao calcular cenários: {e}")
            return None

    def mostrar_analise_completa(self):
        """Exibe análise financeira completa com análise de sensibilidade."""
        if self.dados_relatorio.empty:
            self.text_analise.delete(1.0, tk.END)
            self.text_analise.insert(tk.END, "❌ Adicione transações primeiro!")
            return

        try:
            invest_inicial = float(self.entry_invest_inicial.get() or 0)
            tma_pct = float(self.entry_tma.get() or 12) / 100

            # Calcula indicadores financeiros
            indicadores = self.calcular_indicadores(invest_inicial, tma_pct)
            if not indicadores:
                messagebox.showerror("Erro", "Não foi possível calcular os indicadores!")
                return
                
            vpl = indicadores['vpl']
            tir = indicadores['tir']
            payback_str = indicadores['payback_str']
            vpla = indicadores['vpla']
            net_fluxos = indicadores['net_fluxos']
            
            # 🛑 NOVO: Análise de Sensibilidade
            sensibilidade = self.analisar_sensibilidade(tma_pct, net_fluxos)
            
            # 🛑 NOVO: Análise de Cenários
            cenarios = self.calcular_analise_cenarios(invest_inicial)

            # Resumo financeiro
            total_entradas = self.dados_relatorio['Total Entradas'].sum()
            total_saidas = self.dados_relatorio['Total Saídas'].sum()
            saldo_final = self.dados_relatorio['Saldo Acumulado'].iloc[-1] if len(self.dados_relatorio) > 0 else 0

            analise = f"""
{'='*70}
💹 ANÁLISE FINANCEIRA COMPLETA - CONSTRUTORA
{'='*70}

📊 RESUMO GERAL DO PERÍODO:
• Total Entradas: R$ {total_entradas:,.2f}
• Total Saídas: R$ {total_saidas:,.2f}
• Saldo Final: R$ {saldo_final:,.2f}
• Período: {len(self.dados_relatorio)} meses
• Lucro Bruto: R$ {total_entradas - total_saidas:,.2f}
• Margem Bruta: {(total_entradas - total_saidas)/total_entradas*100 if total_entradas > 0 else 0:.1f}%

💎 ANÁLISE DE VIABILIDADE DO INVESTIMENTO:
• Investimento Inicial: R$ {invest_inicial:,.2f}
• TMA de Referência: {tma_pct*100:.1f}% a.a.
• Valor Presente Líquido (VPL): {'🟢' if vpl >= 0 else '🔴'} R$ {vpl:,.2f}
• Taxa Interna de Retorno (TIR): {'🟢' if tir > tma_pct else '🔴'} {tir*100:.2f}% a.a.
• Payback (Tempo de Retorno): {payback_str}
• VPL Anualizado (VPLA): R$ {vpla:,.2f}

📈 INDICADORES DE VIABILIDADE:
• {'✅' if tir > tma_pct and vpl >= 0 else '❌'} Projeto VIÁVEL
• {'✅' if tir > tma_pct*1.2 and vpl > 0 else '⚠️'} Oportunidade EXCELENTE
• {'✅' if tir > tma_pct*1.5 else '⚠️'} Alta rentabilidade vs mercado
• Margem de Segurança: {((tir/tma_pct)-1)*100:.1f}% (TIR/TMA)

🔬 ANÁLISE DE SENSIBILIDADE (VARIAÇÃO DA TMA):
{'='*70}
• Cenário OTIMISTA (TMA {sensibilidade['rate_otimista']*100:.1f}%):
  VPL = R$ {sensibilidade['vpl_otimista']:,.2f} | Variação: {(sensibilidade['vpl_otimista']/vpl-1)*100 if vpl != 0 else 0:+.1f}%

• Cenário PADRÃO (TMA {tma_pct*100:.1f}%):
  VPL = R$ {vpl:,.2f} (referência)

• Cenário PESSIMISTA (TMA {sensibilidade['rate_pessimista']*100:.1f}%):
  VPL = R$ {sensibilidade['vpl_pessimista']:,.2f} | Variação: {(sensibilidade['vpl_pessimista']/vpl-1)*100 if vpl != 0 else 0:+.1f}%

• Cenário CRÍTICO (TMA {sensibilidade['rate_critico']*100:.1f}%):
  VPL = R$ {sensibilidade['vpl_critico']:,.2f} | Variação: {(sensibilidade['vpl_critico']/vpl-1)*100 if vpl != 0 else 0:+.1f}%

🏗️ ANÁLISE POR CENÁRIOS DE INVESTIMENTO:
{'='*70}
"""
            
            # Adiciona análise de cenários se disponível
            if cenarios:
                for nome, dados in cenarios.items():
                    viabilidade = "VIÁVEL" if dados['vpl'] >= 0 else "INVIÁVEL"
                    analise += f"\n• Cenário {nome.upper()}:"
                    analise += f"\n  Investimento: R$ {dados['investimento']:,.2f}"
                    analise += f"\n  VPL: R$ {dados['vpl']:,.2f} ({viabilidade})"
                    analise += f"\n  TIR: {dados['tir']:.2f}% a.a."
                    
                    if nome == 'Médio':
                        analise += "  ⭐ REFERÊNCIA"
                    
                    analise += "\n"
            
            analise += f"""
{'='*70}
💡 RECOMENDAÇÃO FINANCEIRA:
{self.recomendacao(tir, tma_pct, vpl)}

📋 FLUXO DE CAIXA PARA ANÁLISE (R$):
[Investimento] {net_fluxos[0]:,.2f}
"""
            
            # Adiciona fluxos mensais
            for i, fluxo in enumerate(net_fluxos[1:], 1):
                analise += f"[Mês {i}] {fluxo:,.2f}\n"
            
            analise += f"""
{'='*70}
📊 RESUMO MENSAL:
{self.dados_relatorio.to_string()}
"""
            
            self.text_analise.delete(1.0, tk.END)
            self.text_analise.insert(tk.END, analise)

        except Exception as e:
            messagebox.showerror("Erro", f"Erro na análise: {str(e)}")
            self.text_analise.delete(1.0, tk.END)
            self.text_analise.insert(tk.END, f"❌ Erro na análise: {str(e)}")

    def mostrar_analise_sensibilidade(self):
        """Mostra análise de sensibilidade detalhada em janela separada."""
        if self.dados_relatorio.empty:
            messagebox.showerror("Erro", "Adicione transações primeiro!")
            return
        
        try:
            invest_inicial = float(self.entry_invest_inicial.get() or 0)
            tma_pct = float(self.entry_tma.get() or 12) / 100
            
            # Janela de sensibilidade
            top = tk.Toplevel(self.root)
            top.title("📈 Análise de Sensibilidade Detalhada")
            top.geometry("800x700")
            top.transient(self.root)
            
            # Frame principal
            main_frame = ttk.Frame(top)
            main_frame.pack(fill='both', expand=True, padx=20, pady=20)
            
            ttk.Label(main_frame, text="📈 ANÁLISE DE SENSIBILIDADE COMPLETA", 
                     style='Title.TLabel').pack(pady=10)
            
            # Text widget com scroll
            text_frame = ttk.Frame(main_frame)
            text_frame.pack(fill='both', expand=True, pady=10)
            
            text = tk.Text(text_frame, wrap='word', font=('Consolas', 10), bg='#f8f9fa')
            scrollbar = ttk.Scrollbar(text_frame, orient="vertical", command=text.yview)
            text.configure(yscrollcommand=scrollbar.set)
            
            text.pack(side='left', fill='both', expand=True)
            scrollbar.pack(side='right', fill='y')
            
            # Calcula indicadores
            indicadores = self.calcular_indicadores(invest_inicial, tma_pct)
            if not indicadores:
                text.insert(tk.END, "❌ Não foi possível calcular os indicadores!")
                return
                
            vpl_base = indicadores['vpl']
            tir = indicadores['tir']
            net_fluxos = indicadores['net_fluxos']
            
            # Análise de sensibilidade
            analise = f"""
{'='*80}
📈 ANÁLISE DE SENSIBILIDADE - IMPACTO DA TMA NO VPL
{'='*80}

PARÂMETROS BASE:
• Investimento Inicial: R$ {invest_inicial:,.2f}
• TMA de Referência: {tma_pct*100:.1f}% a.a.
• VPL Base: R$ {vpl_base:,.2f}
• TIR do Projeto: {tir*100:.2f}% a.a.

{'='*80}
IMPACTO DA VARIAÇÃO DA TMA NO VPL:
"""
            
            # Testa diferentes TMAs
            variacoes = [-30, -20, -10, 0, 10, 20, 30]  # Percentual de variação
            text.insert(tk.END, analise)
            
            # Cria tabela de sensibilidade
            text.insert(tk.END, "\n" + "="*80 + "\n")
            text.insert(tk.END, "Variação   |   Nova TMA   |   VPL Calculado   |   Variação do VPL   |   Status\n")
            text.insert(tk.END, "="*80 + "\n")
            
            for var in variacoes:
                nova_tma = tma_pct * (1 + var/100)
                vpl_calculado = self.calculate_npv(nova_tma, net_fluxos)
                variacao_vpl = ((vpl_calculado / vpl_base) - 1) * 100 if vpl_base != 0 else 0
                
                # Determina status
                if vpl_calculado >= 0:
                    status = "✅ VIÁVEL"
                else:
                    status = "❌ INVIÁVEL"
                
                text.insert(tk.END, f"{var:>+6}%   |   {nova_tma*100:>6.1f}%   |   R$ {vpl_calculado:>10,.2f}   |   {variacao_vpl:>+7.1f}%   |   {status}\n")
            
            text.insert(tk.END, "="*80 + "\n\n")
            
            # Análise de break-even da TMA
            text.insert(tk.END, "🔍 ANÁLISE DO PONTO DE EQUILÍBRIO (VPL = 0):\n")
            text.insert(tk.END, "="*80 + "\n")
            
            # Encontra a TMA onde VPL = 0 (break-even)
            try:
                def vpl_func(taxa):
                    return self.calculate_npv(taxa, net_fluxos)
                
                # Busca a taxa onde VPL = 0 (deve estar próxima da TIR)
                tma_break_even = brentq(vpl_func, 0.001, 5.0)  # Entre 0.1% e 500%
                text.insert(tk.END, f"• TMA de Break-even (VPL = 0): {tma_break_even*100:.2f}% a.a.\n")
                text.insert(tk.END, f"• Margem de segurança: {(tir/tma_break_even - 1)*100:.1f}% acima do break-even\n")
                
                if tma_break_even > tma_pct:
                    text.insert(tk.END, f"• ⚠️  Atenção: A TMA atual ({tma_pct*100:.1f}%) está ABAIXO do break-even\n")
                else:
                    text.insert(tk.END, f"• ✅ Seguro: A TMA atual está {((tma_break_even/tma_pct)-1)*100:.1f}% abaixo do break-even\n")
            
            except Exception as e:
                text.insert(tk.END, f"• Não foi possível calcular o ponto de equilíbrio: {str(e)}\n")
            
            text.insert(tk.END, "\n" + "="*80 + "\n")
            text.insert(tk.END, "📊 ANÁLISE DE CENÁRIOS:\n")
            text.insert(tk.END, "="*80 + "\n")
            
            # Cenários de investimento
            cenarios = [-25, 0, 25]  # Variação do investimento
            for var_inv in cenarios:
                novo_invest = invest_inicial * (1 + var_inv/100)
                novos_fluxos = [novo_invest] + net_fluxos[1:]
                vpl_cenario = self.calculate_npv(tma_pct, novos_fluxos)
                tir_cenario = self.calculate_irr(novos_fluxos)
                
                text.insert(tk.END, f"\n• Cenário: Investimento {var_inv:>+6}% (R$ {novo_invest:,.2f})\n")
                text.insert(tk.END, f"  VPL: R$ {vpl_cenario:>10,.2f} | TIR: {tir_cenario*100:>6.2f}%")
                
                if vpl_cenario >= 0:
                    text.insert(tk.END, " | ✅ VIÁVEL\n")
                else:
                    text.insert(tk.END, " | ❌ INVIÁVEL\n")
            
            text.insert(tk.END, "\n" + "="*80 + "\n")
            text.insert(tk.END, "💡 RECOMENDAÇÕES DE DECISÃO:\n")
            text.insert(tk.END, "="*80 + "\n")
            
            # Recomendações baseadas na análise
            if vpl_base >= 0 and tir > tma_pct:
                if tir > tma_pct * 1.3:
                    text.insert(tk.END, "• 🚀 PROJETO ALTAMENTE RECOMENDADO\n")
                    text.insert(tk.END, "  - TIR significativamente acima da TMA\n")
                    text.insert(tk.END, "  - Boa tolerância a aumentos na taxa de desconto\n")
                    text.insert(tk.END, "  - Considerar expansão do investimento\n")
                else:
                    text.insert(tk.END, "• ✅ PROJETO RECOMENDADO\n")
                    text.insert(tk.END, "  - VPL positivo e TIR acima da TMA\n")
                    text.insert(tk.END, "  - Monitorar variações na taxa de juros\n")
            elif vpl_base >= 0 and tir <= tma_pct:
                text.insert(tk.END, "• ⚠️  PROJETO COM RESSALVAS\n")
                text.insert(tk.END, "  - VPL positivo, mas TIR abaixo da TMA\n")
                text.insert(tk.END, "  - Avaliar riscos e considerar TMA mais baixa\n")
            else:
                text.insert(tk.END, "• ❌ PROJETO NÃO RECOMENDADO\n")
                text.insert(tk.END, "  - VPL negativo indica destruição de valor\n")
                text.insert(tk.END, "  - Revisar premissas ou buscar alternativas\n")
            
            text.insert(tk.END, "\n" + "="*80 + "\n")
            text.insert(tk.END, f"Data da análise: {datetime.now().strftime('%d/%m/%Y %H:%M')}\n")
            
            text.config(state='disabled')
            
            # Botão para exportar análise
            btn_frame = ttk.Frame(main_frame)
            btn_frame.pack(pady=10)
            
            ttk.Button(btn_frame, text="💾 Exportar Análise", 
                      command=lambda: self.exportar_analise_sensibilidade(text.get(1.0, tk.END))).pack(side='left', padx=5)
            ttk.Button(btn_frame, text="📊 Gerar Gráfico de Sensibilidade", 
                      command=self.plotar_grafico_sensibilidade).pack(side='left', padx=5)
            ttk.Button(btn_frame, text="Fechar", command=top.destroy).pack(side='left', padx=5)
            
        except Exception as e:
            messagebox.showerror("Erro", f"Erro na análise de sensibilidade: {str(e)}")

    def plotar_grafico_sensibilidade(self):
        """Plota gráfico de sensibilidade do VPL em relação à TMA."""
        if self.dados_relatorio.empty:
            messagebox.showerror("Erro", "Adicione transações primeiro!")
            return
        
        try:
            invest_inicial = float(self.entry_invest_inicial.get() or 0)
            tma_pct = float(self.entry_tma.get() or 12) / 100
            
            indicadores = self.calcular_indicadores(invest_inicial, tma_pct)
            if not indicadores:
                return
                
            net_fluxos = indicadores['net_fluxos']
            
            # Gera diferentes taxas de desconto
            taxas = np.linspace(0.01, 0.30, 50)  # De 1% a 30%
            vpls = [self.calculate_npv(taxa, net_fluxos) for taxa in taxas]
            
            # Plota gráfico
            fig, ax = plt.subplots(figsize=(12, 7), facecolor='white')
            
            # Linha do VPL
            ax.plot(taxas*100, vpls, linewidth=3, color='#2E8B57', label='VPL')
            ax.axhline(y=0, color='red', linestyle='--', alpha=0.5, label='VPL = 0')
            ax.axvline(x=tma_pct*100, color='blue', linestyle='--', alpha=0.5, label=f'TMA = {tma_pct*100:.1f}%')
            
            # Preenche área positiva
            ax.fill_between(taxas*100, vpls, 0, where=(np.array(vpls) >= 0), 
                           alpha=0.3, color='green', label='Viável (VPL ≥ 0)')
            ax.fill_between(taxas*100, vpls, 0, where=(np.array(vpls) < 0), 
                           alpha=0.3, color='red', label='Inviável (VPL < 0)')
            
            ax.set_title('📈 Análise de Sensibilidade: VPL vs Taxa de Desconto (TMA)', 
                        fontsize=16, fontweight='bold', pad=15)
            ax.set_xlabel('Taxa de Desconto - TMA (% a.a.)', fontsize=12)
            ax.set_ylabel('Valor Presente Líquido - VPL (R$)', fontsize=12)
            ax.grid(True, alpha=0.3)
            ax.legend(loc='upper right')
            
            # Formatação
            ax.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'R$ {x:,.0f}'))
            ax.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'{x:.1f}%'))
            
            # Destaca ponto da TIR
            tir = indicadores['tir']
            vpl_tir = self.calculate_npv(tir, net_fluxos)
            if 0.01 <= tir <= 0.30:
                ax.scatter(tir*100, vpl_tir, color='orange', s=100, zorder=5, 
                          label=f'TIR = {tir*100:.1f}%')
                ax.annotate(f'TIR: {tir*100:.1f}%', 
                           xy=(tir*100, vpl_tir),
                           xytext=(tir*100+1, vpl_tir + max(vpls)*0.1),
                           arrowprops=dict(arrowstyle='->', color='orange'),
                           fontsize=10, fontweight='bold')
            
            plt.tight_layout()
            
            # Mostra em nova janela
            top = tk.Toplevel(self.root)
            top.title("📊 Gráfico de Sensibilidade")
            top.geometry("1000x800")
            
            canvas = FigureCanvasTkAgg(fig, master=top)
            canvas.draw()
            canvas.get_tk_widget().pack(fill='both', expand=True, padx=20, pady=20)
            
            # Botão para salvar
            ttk.Button(top, text="💾 Salvar Gráfico", 
                      command=lambda: self.exportar_grafico_sensibilidade(fig)).pack(pady=10)
            
        except Exception as e:
            messagebox.showerror("Erro", f"Erro ao plotar gráfico: {str(e)}")

    def exportar_analise_sensibilidade(self, conteudo):
        """Exporta análise de sensibilidade para arquivo."""
        file = filedialog.asksaveasfilename(
            defaultextension=".txt",
            filetypes=[("Arquivo de Texto", "*.txt"), ("Todos os arquivos", "*.*")],
            initialfile=f"analise_sensibilidade_{datetime.now().strftime('%Y%m%d_%H%M')}.txt"
        )
        
        if file:
            try:
                with open(file, 'w', encoding='utf-8') as f:
                    f.write(conteudo)
                messagebox.showinfo("✅ Exportado!", f"Análise salva em:\n{file}")
            except Exception as e:
                messagebox.showerror("Erro", f"Falha ao exportar: {str(e)}")

    def exportar_grafico_sensibilidade(self, fig):
        """Exporta gráfico de sensibilidade."""
        file = filedialog.asksaveasfilename(
            defaultextension=".png",
            filetypes=[("PNG", "*.png"), ("PDF", "*.pdf"), ("SVG", "*.svg")],
            initialfile=f"grafico_sensibilidade_{datetime.now().strftime('%Y%m%d')}.png"
        )
        
        if file:
            try:
                fig.savefig(file, dpi=300, bbox_inches='tight')
                messagebox.showinfo("✅ Exportado!", f"Gráfico salvo em:\n{file}")
            except Exception as e:
                messagebox.showerror("Erro", f"Falha ao exportar gráfico: {str(e)}")

    def recomendacao(self, tir, tma, vpl):
        if tir > tma * 1.3 and vpl > 0:
            return "🚀 APROVAR IMEDIATAMENTE - Projeto com excelente retorno e baixo risco!"
        elif tir > tma * 1.1 and vpl >= 0:
            return "✅ APROVAR - Projeto viável com bom retorno sobre o capital."
        elif tir > tma and vpl >= 0:
            return "⚠️ APROVAR COM RESSALVAS - Projeto marginalmente viável. Monitorar riscos."
        elif 0.9 < tir/tma < 1 and vpl < 0:
            return "🔍 REANALISAR - Projeto próximo da viabilidade. Revisar premissas."
        else:
            return "❌ REJEITAR - Projeto destrói valor. Buscar alternativas de investimento."

    def calculate_npv(self, rate, cash_flows):
        return sum(cf / (1 + rate) ** i for i, cf in enumerate(cash_flows))

    def calculate_irr(self, cash_flows):
        try:
            return brentq(lambda r: self.calculate_npv(r, cash_flows), 0.001, 5.0)
        except:
            return 0

    def mostrar_relatorio_obra(self):
        """Mostra relatório de custos por obra."""
        # Obtém lista única de obras
        obras_entradas = self.manager.entradas_df['obra_projeto'].dropna().unique().tolist()
        obras_saidas = self.manager.saidas_df['obra_projeto'].dropna().unique().tolist()
        todas_obras = sorted(set(obras_entradas + obras_saidas))
        
        if not todas_obras:
            messagebox.showinfo("Informação", "Nenhuma obra/projeto cadastrada.")
            return
            
        obras = ["Todas"] + todas_obras
        
        # Janela de seleção
        top = tk.Toplevel(self.root)
        top.title("📊 Relatório por Obra/Projeto")
        top.geometry("600x500")
        top.transient(self.root)
        top.grab_set()
        
        main_frame = ttk.Frame(top)
        main_frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        ttk.Label(main_frame, text="Selecione a Obra/Projeto:", style='Header.TLabel').pack(pady=10)
        
        obra_var = tk.StringVar(value="Todas")
        obra_combo = ttk.Combobox(main_frame, textvariable=obra_var, values=obras, 
                                 state="readonly", font=('Arial', 11), width=40)
        obra_combo.pack(pady=10)
        
        # Frame para o relatório com scroll
        relatorio_frame = ttk.Frame(main_frame)
        relatorio_frame.pack(fill='both', expand=True, pady=10)
        
        # Text widget com scroll
        relatorio_text = tk.Text(relatorio_frame, wrap='word', height=15, width=70, 
                                font=('Consolas', 10), bg='#f8f9fa')
        scrollbar = ttk.Scrollbar(relatorio_frame, orient="vertical", command=relatorio_text.yview)
        relatorio_text.configure(yscrollcommand=scrollbar.set)
        
        relatorio_text.pack(side='left', fill='both', expand=True)
        scrollbar.pack(side='right', fill='y')
        
        def atualizar_relatorio():
            obra = obra_var.get()
            
            # Entradas para a obra
            if obra == "Todas":
                entradas_total = self.manager.entradas_df['valor'].sum()
                saidas_total = self.manager.saidas_df['valor'].sum()
            else:
                entradas_total = self.manager.entradas_df[self.manager.entradas_df['obra_projeto'] == obra]['valor'].sum()
                saidas_total = self.manager.saidas_df[self.manager.saidas_df['obra_projeto'] == obra]['valor'].sum()
            
            # Relatório de custos por categoria
            relatorio = self.manager.relatorio_custos_por_obra(obra)
            
            relatorio_text.delete(1.0, tk.END)
            
            if obra == "Todas":
                relatorio_text.insert(tk.END, f"📊 RELATÓRIO CONSOLIDADO - TODAS AS OBRAS\n")
            else:
                relatorio_text.insert(tk.END, f"📊 RELATÓRIO POR OBRA: {obra}\n")
            
            relatorio_text.insert(tk.END, "="*60 + "\n\n")
            
            relatorio_text.insert(tk.END, "💰 RESUMO FINANCEIRO:\n")
            relatorio_text.insert(tk.END, f"• Total Entradas: R$ {entradas_total:,.2f}\n")
            relatorio_text.insert(tk.END, f"• Total Saídas: R$ {saidas_total:,.2f}\n")
            relatorio_text.insert(tk.END, f"• Saldo: R$ {entradas_total - saidas_total:,.2f}\n")
            relatorio_text.insert(tk.END, f"• Margem: {(entradas_total - saidas_total)/entradas_total*100 if entradas_total > 0 else 0:.1f}%\n\n")
            
            relatorio_text.insert(tk.END, "📋 DISTRIBUIÇÃO DE CUSTOS POR CATEGORIA:\n")
            relatorio_text.insert(tk.END, "="*60 + "\n")
            
            if relatorio.empty:
                relatorio_text.insert(tk.END, "⚠️ Nenhum custo registrado para esta obra\n")
            else:
                total_custos = relatorio.sum()
                for categoria, valor in relatorio.items():
                    percentual = (valor / total_custos * 100) if total_custos > 0 else 0
                    barra = "█" * int(percentual / 2)  # Barra de progresso visual
                    relatorio_text.insert(tk.END, f"\n• {categoria}:\n")
                    relatorio_text.insert(tk.END, f"  R$ {valor:,.2f} ({percentual:.1f}%) {barra}\n")
                
                relatorio_text.insert(tk.END, "\n" + "="*60 + "\n")
                relatorio_text.insert(tk.END, f"💰 TOTAL DE CUSTOS: R$ {total_custos:,.2f}\n")
                
                # Análise de custos
                if total_custos > 0:
                    maior_categoria = relatorio.idxmax()
                    maior_valor = relatorio.max()
                    percent_maior = (maior_valor / total_custos * 100)
                    
                    relatorio_text.insert(tk.END, f"\n🔍 ANÁLISE:\n")
                    relatorio_text.insert(tk.END, f"• Maior custo: {maior_categoria} (R$ {maior_valor:,.2f} - {percent_maior:.1f}%)\n")
                    if percent_maior > 50:
                        relatorio_text.insert(tk.END, "  ⚠️ Atenção: Esta categoria representa mais de 50% dos custos!\n")
        
        ttk.Button(main_frame, text="🔍 Gerar Relatório", command=atualizar_relatorio, 
                  style='Accent.TButton').pack(pady=10)
        ttk.Button(main_frame, text="💾 Exportar para CSV", 
                  command=lambda: self.exportar_relatorio_obra(obra_var.get())).pack(pady=5)
        
        atualizar_relatorio()  # Gera relatório inicial

    def exportar_relatorio_obra(self, obra):
        """Exporta relatório da obra para CSV."""
        if not obra:
            return
            
        file = filedialog.asksaveasfilename(
            defaultextension=".csv",
            filetypes=[("CSV", "*.csv"), ("Todos os arquivos", "*.*")],
            initialfile=f"relatorio_obra_{obra.replace('/', '_')}.csv"
        )
        
        if file:
            try:
                # Coleta dados da obra
                if obra == "Todas":
                    entradas_obra = self.manager.entradas_df
                    saidas_obra = self.manager.saidas_df
                else:
                    entradas_obra = self.manager.entradas_df[self.manager.entradas_df['obra_projeto'] == obra]
                    saidas_obra = self.manager.saidas_df[self.manager.saidas_df['obra_projeto'] == obra]
                
                # Cria relatório consolidado
                with open(file, 'w', encoding='utf-8') as f:
                    f.write(f"Relatório da Obra: {obra}\n")
                    f.write(f"Data da geração: {datetime.now().strftime('%d/%m/%Y %H:%M')}\n\n")
                    
                    f.write("RESUMO FINANCEIRO:\n")
                    total_entradas = entradas_obra['valor'].sum()
                    total_saidas = saidas_obra['valor'].sum()
                    f.write(f"Total Entradas,R$ {total_entradas:.2f}\n")
                    f.write(f"Total Saídas,R$ {total_saidas:.2f}\n")
                    f.write(f"Saldo,R$ {total_entradas - total_saidas:.2f}\n")
                    f.write(f"Margem,{(total_entradas - total_saidas)/total_entradas*100 if total_entradas > 0 else 0:.1f}%\n\n")
                    
                    f.write("ENTRADAS DETALHADAS:\n")
                    if not entradas_obra.empty:
                        entradas_obra.to_csv(f, index=False, mode='a')
                    else:
                        f.write("Nenhuma entrada registrada\n")
                    
                    f.write("\nSAÍDAS DETALHADAS:\n")
                    if not saidas_obra.empty:
                        saidas_obra.to_csv(f, index=False, mode='a')
                    else:
                        f.write("Nenhuma saída registrada\n")
                    
                    f.write("\nCUSTOS POR CATEGORIA:\n")
                    relatorio = self.manager.relatorio_custos_por_obra(obra)
                    if not relatorio.empty:
                        for categoria, valor in relatorio.items():
                            f.write(f"{categoria},R$ {valor:.2f}\n")
                
                messagebox.showinfo("✅ Exportado!", f"Relatório exportado para:\n{file}")
                
            except Exception as e:
                messagebox.showerror("Erro", f"Falha ao exportar: {str(e)}")

    def exportar_dados(self):
        """Exporta todos os dados para CSV."""
        try:
            file = filedialog.asksaveasfilename(
                defaultextension=".zip",
                filetypes=[("ZIP com CSVs", "*.zip"), ("CSV de Entradas", "entradas.csv"), ("CSV de Saídas", "saidas.csv")],
                initialfile="dados_construtora.zip"
            )
            
            if file:
                import zipfile
                
                with zipfile.ZipFile(file, 'w') as zipf:
                    # Adiciona arquivos CSV ao ZIP
                    if os.path.exists(self.manager.ENTRADAS_FILE):
                        zipf.write(self.manager.ENTRADAS_FILE, 'entradas.csv')
                    if os.path.exists(self.manager.SAIDAS_FILE):
                        zipf.write(self.manager.SAIDAS_FILE, 'saidas.csv')
                    
                    # Adiciona relatório consolidado
                    relatorio_file = "relatorio_consolidado.txt"
                    with open(relatorio_file, 'w', encoding='utf-8') as f:
                        f.write("RELATÓRIO CONSOLIDADO - SISTEMA DE FLUXO DE CAIXA\n")
                        f.write("="*60 + "\n\n")
                        f.write(self.text_analise.get(1.0, tk.END))
                    
                    zipf.write(relatorio_file, 'relatorio.txt')
                    os.remove(relatorio_file)  # Remove arquivo temporário
                
                messagebox.showinfo("✅ Exportado!", f"Dados exportados para:\n{file}")
                
        except Exception as e:
            messagebox.showerror("Erro", f"Falha ao exportar: {str(e)}")

    def exportar_grafico(self):
        """Exporta o gráfico atual como imagem."""
        if self.dados_relatorio.empty:
            messagebox.showerror("Erro", "Sem dados para exportar gráfico!")
            return
        
        file = filedialog.asksaveasfilename(
            defaultextension=".png",
            filetypes=[("PNG", "*.png"), ("PDF", "*.pdf"), ("SVG", "*.svg")],
            initialfile=f"grafico_fluxo_caixa_{datetime.now().strftime('%Y%m%d')}"
        )
        
        if file:
            # Recria o gráfico em alta resolução
            fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14, 12), facecolor='white')
            meses = self.dados_relatorio.index
            
            # Gráfico 1: Saldo Acumulado
            ax1.plot(meses, self.dados_relatorio['Saldo Acumulado'], marker='o', linewidth=3, 
                    label='Saldo Acumulado', color='#2E8B57')
            ax1.fill_between(meses, self.dados_relatorio['Saldo Acumulado'], alpha=0.3, color='#2E8B57')
            ax1.set_title('📈 Evolução do Saldo Acumulado - Construtora', fontsize=16, fontweight='bold', pad=15)
            ax1.set_ylabel('Saldo Acumulado (R$)', fontsize=13, color='#2E8B57')
            ax1.tick_params(axis='y', labelcolor='#2E8B57')
            ax1.grid(True, alpha=0.3)
            ax1.legend(loc='upper left', fontsize=12)
            ax1.set_xticks(range(len(meses)))
            ax1.set_xticklabels(meses, rotation=45, ha='right', fontsize=11)
            
            # Formatação de valores
            ax1.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'R$ {x:,.0f}'))
            
            # Gráfico 2: Entradas vs Saídas
            width = 0.35
            x = np.arange(len(meses))
            
            ax2.bar(x - width/2, self.dados_relatorio['Total Entradas'], width=width, 
                    alpha=0.8, label='Entradas', color='#32CD32', edgecolor='black', linewidth=1)
            ax2.bar(x + width/2, self.dados_relatorio['Total Saídas'], width=width, 
                    alpha=0.8, label='Saídas', color='#FF6347', edgecolor='black', linewidth=1)
            
            ax2.set_title('📊 Entradas vs Saídas Mensais', fontsize=16, fontweight='bold', pad=15)
            ax2.set_xlabel('Mês', fontsize=13)
            ax2.set_ylabel('Valor (R$)', fontsize=13)
            ax2.set_xticks(x)
            ax2.set_xticklabels(meses, rotation=45, ha='right', fontsize=11)
            ax2.grid(True, alpha=0.3, axis='y')
            ax2.legend(loc='upper left', fontsize=12)
            
            # Adiciona valores nas barras
            for i, (ent, sai) in enumerate(zip(self.dados_relatorio['Total Entradas'], self.dados_relatorio['Total Saídas'])):
                if ent > 0:
                    ax2.text(i - width/2, ent + max(ent, sai)*0.01, f'R$ {ent:,.0f}', 
                            ha='center', va='bottom', fontsize=9, fontweight='bold')
                if sai > 0:
                    ax2.text(i + width/2, sai + max(ent, sai)*0.01, f'R$ {sai:,.0f}', 
                            ha='center', va='bottom', fontsize=9, fontweight='bold')
            
            # Formatação de valores
            ax2.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'R$ {x:,.0f}'))
            
            plt.tight_layout()
            plt.savefig(file, dpi=300, bbox_inches='tight')
            plt.close()
            
            messagebox.showinfo("✅ Exportado!", f"Gráfico salvo em:\n{file}")

    def mostrar_ajuda(self):
        """Mostra janela de ajuda sobre categorias."""
        ajuda_text = """
🏗️ CATEGORIAS PARA CONSTRUTORA

📥 ENTRADAS (Receitas):
• Medição de Obra: Recebimento por etapas concluídas
• Venda de Imóvel: Venda de unidades prontas
• Serviços Extras: Serviços avulsos não inclusos no contrato
• Empréstimo/Financiamento: Captação de recursos financeiros
• Capital Social: Aportes de sócios
• Venda de Ativos: Venda de máquinas/equipamentos
• Outros / Customizável: Outras receitas não classificadas

📤 SAÍDAS (Custos/Despesas):
• Mão de Obra: Salários, encargos, serviços terceirizados
• Materiais: Todos os insumos físicos da construção
• Equipamentos: Aluguel, manutenção, combustível
• Administrativo: Despesas do escritório
• Impostos e Taxas: Obrigações governamentais
• Serviços: Projetos, consultorias, laudos
• Marketing e Vendas: Publicidade, comissões
• Financeiro: Juros, tarifas bancárias
• Outros / Customizável: Despesas não classificadas

💡 DICAS:
1. Use descrições claras para fácil identificação
2. Sempre informe a obra/projeto relacionada
3. Registre imediatamente após cada transação
4. Revise periodicamente os relatórios por obra
5. Use as categorias para análise de custos
"""
        
        top = tk.Toplevel(self.root)
        top.title("❓ Ajuda - Categorias")
        top.geometry("500x600")
        top.transient(self.root)
        
        text = tk.Text(top, wrap='word', font=('Arial', 10), bg='#f8f9fa')
        text.insert(1.0, ajuda_text)
        text.config(state='disabled')
        
        scrollbar = ttk.Scrollbar(top, orient="vertical", command=text.yview)
        text.configure(yscrollcommand=scrollbar.set)
        
        text.pack(side='left', fill='both', expand=True, padx=10, pady=10)
        scrollbar.pack(side='right', fill='y')
        
        ttk.Button(top, text="Fechar", command=top.destroy).pack(pady=10)

    def atualizar_tudo(self):
        """Atualiza todos os componentes da interface."""
        self.atualizar_dados_relatorio()
        self.atualizar_tabela_agregada()
        self.plotar_grafico()
        self.mostrar_analise_completa()

    def salvar_dados(self):
        """Salva os dados através do manager."""
        if self.manager.salvar_dados():
            messagebox.showinfo("✅ Salvo!", "Dados salvos automaticamente em:\n• entradas.csv\n• saidas.csv")
        else:
            messagebox.showerror("Erro", "Falha ao salvar os dados.")

    def limpar_campos(self):
        """Limpa os campos do formulário de entrada."""
        self.entry_descricao.delete(0, tk.END)
        self.entry_obra.delete(0, tk.END)
        self.entry_valor.delete(0, tk.END)
        self.entry_cliente.delete(0, tk.END)
        
        # Restaura valores padrão
        if self.tipo_transacao == "entrada":
            self.combo_categoria.set(self.CATEGORIAS_ENTRADA[0])
        else:
            self.combo_categoria.set(self.CATEGORIAS_SAIDA[0])
            self.entry_fornecedor.delete(0, tk.END)
            self.combo_subcategoria.set('')
            self.combo_meio_pagamento.set(self.MEIO_PAGAMENTO[0])
        
        # Mantém a data atual
        self.entry_data.delete(0, tk.END)
        self.entry_data.insert(0, datetime.now().strftime("%d/%m/%Y"))
        
        # Foca no primeiro campo
        self.entry_descricao.focus()

    def limpar_tudo(self):
        """Limpa todos os dados após confirmação."""
        if messagebox.askyesno("Confirmar", "🗑️ Limpar TODOS os dados? Isso não pode ser desfeito!"):
            self.manager.entradas_df = pd.DataFrame(columns=self.manager.COLS_ENTRADAS)
            self.manager.saidas_df = pd.DataFrame(columns=self.manager.COLS_SAIDAS)
            self.manager.salvar_dados()
            self.atualizar_tudo()
            messagebox.showinfo("✅ Limpo!", "Todos os dados foram removidos!")

# ==============================================
# 3. EXECUÇÃO PRINCIPAL
# ==============================================

if __name__ == "__main__":
    root = tk.Tk()
    app = FluxoCaixaApp(root)
    root.mainloop()