import tkinter as tk
from tkinter import ttk, messagebox
import matplotlib
# Configura o backend do Matplotlib para funcionar com Tkinter
matplotlib.use('TkAgg')

from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np

class AppPessoas(tk.Tk):
    """Classe principal da aplicação Tkinter."""
    def __init__(self):
        super().__init__()
        self.title("Cadastro e Gráfico de Pessoas")
        self.geometry("800x600")

        # Lista para armazenar os dados de pessoas: [{"idade": 30, "peso": 75}, ...]
        self.dados_pessoas = []

        # Configura as abas
        self.notebook = ttk.Notebook(self)
        self.notebook.pack(pady=10, padx=10, expand=True, fill="both")

        # Cria as abas
        self.aba_cadastro = ttk.Frame(self.notebook)
        self.aba_grafico = ttk.Frame(self.notebook)

        self.notebook.add(self.aba_cadastro, text="1. Cadastro")
        self.notebook.add(self.aba_grafico, text="2. Gráfico")
        
        # Vincula a função de atualização ao evento de mudança de aba
        self.notebook.bind("<<NotebookTabChanged>>", self.on_tab_change)

        # Configura o conteúdo de cada aba
        self.setup_aba_cadastro()
        self.setup_aba_grafico()

    def setup_aba_cadastro(self):
        """Configura os widgets na aba de Cadastro."""
        
        # Frame principal para centralizar
        frame_cadastro = ttk.Frame(self.aba_cadastro, padding="20")
        frame_cadastro.pack(expand=True, anchor="center")

        # Rótulo e campo para Idade
        ttk.Label(frame_cadastro, text="Idade (anos):").grid(row=0, column=0, pady=10, sticky="w")
        self.entry_idade = ttk.Entry(frame_cadastro, width=15)
        self.entry_idade.grid(row=0, column=1, pady=10, padx=5, sticky="ew")

        # Rótulo e campo para Peso
        ttk.Label(frame_cadastro, text="Peso (kg):").grid(row=1, column=0, pady=10, sticky="w")
        self.entry_peso = ttk.Entry(frame_cadastro, width=15)
        self.entry_peso.grid(row=1, column=1, pady=10, padx=5, sticky="ew")

        # Botão para adicionar
        botao_adicionar = ttk.Button(frame_cadastro, text="Adicionar Pessoa", command=self.adicionar_pessoa)
        botao_adicionar.grid(row=2, column=0, columnspan=2, pady=20)
        
        # Rótulo para mostrar a contagem de pessoas
        self.label_contagem = ttk.Label(frame_cadastro, text=f"Pessoas cadastradas: {len(self.dados_pessoas)}")
        self.label_contagem.grid(row=3, column=0, columnspan=2, pady=10)

    def adicionar_pessoa(self):
        """Coleta, valida e armazena os dados de idade e peso."""
        try:
            idade = int(self.entry_idade.get())
            peso = float(self.entry_peso.get().replace(',', '.'))
            
            if idade <= 0 or peso <= 0:
                 raise ValueError("Idade e Peso devem ser maiores que zero.")

            # Armazena os dados
            self.dados_pessoas.append({"idade": idade, "peso": peso})
            
            # Limpa os campos de entrada
            self.entry_idade.delete(0, tk.END)
            self.entry_peso.delete(0, tk.END)
            
            # Atualiza a contagem
            self.label_contagem.config(text=f"Pessoas cadastradas: {len(self.dados_pessoas)}")
            
            messagebox.showinfo("Sucesso", f"Pessoa adicionada: Idade {idade}, Peso {peso}kg.")
            
        except ValueError as e:
            messagebox.showerror("Erro de Entrada", f"Por favor, insira valores válidos: {e}")
        except Exception as e:
            messagebox.showerror("Erro", f"Ocorreu um erro: {e}")

    def setup_aba_grafico(self):
        """Configura a área de desenho do gráfico na aba de Gráfico."""
        
        # Cria a Figura (área de desenho) do Matplotlib
        self.figura = Figure(figsize=(5, 5), dpi=100)
        self.eixo = self.figura.add_subplot(111)

        # Cria o Canvas do Tkinter a partir da Figura
        self.canvas = FigureCanvasTkAgg(self.figura, master=self.aba_grafico)
        
        # Adiciona o widget do canvas à aba
        self.canvas_widget = self.canvas.get_tk_widget()
        self.canvas_widget.pack(side=tk.TOP, fill=tk.BOTH, expand=1)

        # Desenha o gráfico inicial vazio
        self.plotar_grafico()

    def plotar_grafico(self):
        """Gera o gráfico de Dispersão (Scatter Plot) com frequência de peso por idade."""
        
        # Limpa o gráfico anterior
        self.eixo.clear()

        if not self.dados_pessoas:
            self.eixo.text(0.5, 0.5, 'Nenhum dado cadastrado para exibir.', 
                           ha='center', va='center', transform=self.eixo.transAxes)
            self.figura.canvas.draw()
            return

        # 1. Preparar os dados para contagem de frequência
        # Cria tuplas (idade, peso) e conta a frequência de cada combinação
        combinacoes = [(d['idade'], d['peso']) for d in self.dados_pessoas]
        from collections import Counter
        frequencias = Counter(combinacoes)

        # 2. Separar os dados contados
        idades = [c[0] for c in frequencias.keys()]
        pesos = [c[1] for c in frequencias.keys()]
        contagens = np.array(list(frequencias.values()))

        # 3. Mapear a contagem para o tamanho do ponto (escala visual)
        # O tamanho (s) dos pontos no scatter plot será proporcional à frequência
        # Usamos log para suavizar grandes diferenças e adicionamos um offset
        tamanhos = (np.log(contagens + 1) * 200) + 50
        
        # 4. Desenhar o gráfico de dispersão (Scatter Plot)
        scatter = self.eixo.scatter(idades, pesos, s=tamanhos, alpha=0.6, edgecolors='w', linewidth=1)

        # 5. Configurar rótulos e título
        self.eixo.set_title("Frequência de Peso por Idade (Tamanho do Ponto = Frequência)")
        self.eixo.set_xlabel("Idade (anos)")
        self.eixo.set_ylabel("Peso (kg)")
        self.eixo.grid(True, linestyle='--', alpha=0.7)
        self.eixo.margins(0.1)
        
        # Garante que os valores dos eixos sejam inteiros se forem todos inteiros
        if all(isinstance(i, int) for i in idades) and idades:
            self.eixo.xaxis.set_major_locator(matplotlib.ticker.MaxNLocator(integer=True))

        # 6. Forçar o redesenho do canvas
        self.figura.canvas.draw()

    def on_tab_change(self, event):
        """Chamado quando o usuário muda de aba. Atualiza o gráfico se for para a aba de Gráfico."""
        aba_selecionada = self.notebook.tab(self.notebook.select(), "text")
        
        if aba_selecionada == "2. Gráfico":
            self.plotar_grafico()

# Ponto de entrada do programa
if __name__ == "__main__":
    app = AppPessoas()
    app.mainloop()