"""Ponto de entrada da aplicação Tkinter — Caixa MEI (metodologia)."""
import os
import sys
import tkinter as tk
from tkinter import ttk, filedialog, messagebox

from .domain.models import Lancamento
from .domain.plano_contas import CATEGORIAS_MEI, categorias_de
from .repository import csv_repo
from .analysis.consolidacao import consolidar_mensal
from .analysis.finance import vpl, tir, payback

DEFAULT_CSV = "fluxo_caixa.csv"


class App(tk.Tk):
    def __init__(self) -> None:
        super().__init__()
        self.title("Caixa MEI — Nirlene Contabilidade (metodologia)")
        self.geometry("960x640")
        self.lancamentos: list[Lancamento] = []
        self.csv_path: str = DEFAULT_CSV
        self._build()
        self._carregar_inicial()

    def _build(self) -> None:
        nb = ttk.Notebook(self)
        nb.pack(fill="both", expand=True)
        self.tab_lanc = ttk.Frame(nb); nb.add(self.tab_lanc, text="Lançamentos")
        self.tab_resumo = ttk.Frame(nb); nb.add(self.tab_resumo, text="Resumo mensal")
        self.tab_analise = ttk.Frame(nb); nb.add(self.tab_analise, text="Análise (VPL/TIR)")
        self._build_lanc(self.tab_lanc)
        self._build_resumo(self.tab_resumo)
        self._build_analise(self.tab_analise)

    # ---------- Lançamentos ----------
    def _build_lanc(self, p: ttk.Frame) -> None:
        bar = ttk.Frame(p); bar.pack(fill="x", padx=6, pady=6)
        ttk.Button(bar, text="Carregar CSV", command=self.acao_carregar).pack(side="left")
        ttk.Button(bar, text="Salvar CSV", command=self.acao_salvar).pack(side="left", padx=4)
        ttk.Button(bar, text="Novo lançamento", command=self.acao_novo).pack(side="left", padx=4)
        ttk.Button(bar, text="Remover selecionado", command=self.acao_remover).pack(side="left", padx=4)

        cols = ("data", "tipo", "escopo", "categoria", "valor", "descricao")
        self.tree = ttk.Treeview(p, columns=cols, show="headings")
        for c in cols:
            self.tree.heading(c, text=c)
            self.tree.column(c, width=120, anchor="w")
        self.tree.column("valor", anchor="e")
        self.tree.pack(fill="both", expand=True, padx=6, pady=6)

    def _refresh_lanc(self) -> None:
        self.tree.delete(*self.tree.get_children())
        for i, l in enumerate(self.lancamentos):
            self.tree.insert("", "end", iid=str(i), values=(
                l.data, l.tipo, l.escopo, l.categoria, f"{l.valor:.2f}", l.descricao,
            ))
        self._refresh_resumo()

    def acao_carregar(self) -> None:
        path = filedialog.askopenfilename(filetypes=[("CSV", "*.csv")])
        if not path:
            return
        ok, erros = csv_repo.carregar(path)
        self.lancamentos = ok
        self.csv_path = path
        if erros:
            messagebox.showwarning("Avisos", "\n".join(erros[:10]))
        self._refresh_lanc()

    def acao_salvar(self) -> None:
        path = filedialog.asksaveasfilename(defaultextension=".csv", initialfile=os.path.basename(self.csv_path))
        if not path:
            return
        csv_repo.salvar(path, self.lancamentos)
        self.csv_path = path
        messagebox.showinfo("OK", f"{len(self.lancamentos)} lançamento(s) salvo(s) em {path}.")

    def acao_novo(self) -> None:
        DialogLancamento(self, on_save=self._adicionar)

    def _adicionar(self, l: Lancamento) -> None:
        self.lancamentos.append(l)
        self._refresh_lanc()

    def acao_remover(self) -> None:
        sel = self.tree.selection()
        if not sel:
            return
        idx = int(sel[0])
        del self.lancamentos[idx]
        self._refresh_lanc()

    # ---------- Resumo ----------
    def _build_resumo(self, p: ttk.Frame) -> None:
        self.txt_resumo = tk.Text(p, font=("Consolas", 10))
        self.txt_resumo.pack(fill="both", expand=True, padx=6, pady=6)

    def _refresh_resumo(self) -> None:
        self.txt_resumo.delete("1.0", "end")
        for escopo in ("pj", "pf"):
            resumo = consolidar_mensal(self.lancamentos, escopo)  # type: ignore[arg-type]
            self.txt_resumo.insert("end", f"=== {'EMPRESA (PJ)' if escopo == 'pj' else 'PESSOAL (PF)'} ===\n")
            self.txt_resumo.insert("end", f"{'Mês':<10}{'Entradas':>14}{'Saídas':>14}{'Saldo':>14}\n")
            for r in resumo:
                self.txt_resumo.insert("end", f"{r.mes:<10}{r.entradas:>14.2f}{r.saidas:>14.2f}{r.saldo:>14.2f}\n")
            self.txt_resumo.insert("end", "\n")

    # ---------- Análise ----------
    def _build_analise(self, p: ttk.Frame) -> None:
        bar = ttk.Frame(p); bar.pack(fill="x", padx=6, pady=6)
        ttk.Label(bar, text="Investimento:").pack(side="left")
        self.v_inv = tk.StringVar(value="10000")
        ttk.Entry(bar, textvariable=self.v_inv, width=12).pack(side="left", padx=4)
        ttk.Label(bar, text="TMA (% a.m.):").pack(side="left")
        self.v_tma = tk.StringVar(value="1.0")
        ttk.Entry(bar, textvariable=self.v_tma, width=8).pack(side="left", padx=4)
        ttk.Label(bar, text="Escopo:").pack(side="left")
        self.v_esc = tk.StringVar(value="pj")
        ttk.Combobox(bar, textvariable=self.v_esc, values=["pj", "pf"], width=5, state="readonly").pack(side="left", padx=4)
        ttk.Button(bar, text="Calcular", command=self.acao_calcular).pack(side="left", padx=8)

        self.txt_analise = tk.Text(p, font=("Consolas", 10))
        self.txt_analise.pack(fill="both", expand=True, padx=6, pady=6)

    def acao_calcular(self) -> None:
        try:
            inv = -abs(float(self.v_inv.get()))
            tma = float(self.v_tma.get()) / 100
        except ValueError:
            messagebox.showerror("Erro", "Valores numéricos inválidos.")
            return
        escopo = self.v_esc.get()
        resumo = consolidar_mensal(self.lancamentos, escopo)  # type: ignore[arg-type]
        if not resumo:
            messagebox.showinfo("Vazio", "Sem dados para o escopo escolhido.")
            return
        fluxos = [inv] + [r.saldo for r in resumo]
        v = vpl(tma, fluxos)
        t = tir(fluxos)
        p = payback(fluxos, tma)
        self.txt_analise.delete("1.0", "end")
        self.txt_analise.insert("end", f"Fluxos ({len(fluxos)}):\n")
        for i, f in enumerate(fluxos):
            self.txt_analise.insert("end", f"  t={i:>2}: {f:>12.2f}\n")
        self.txt_analise.insert("end", f"\nVPL @ TMA {tma*100:.2f}%: R$ {v:,.2f}\n")
        self.txt_analise.insert("end", f"TIR: {t*100:.4f}% a.m.\n" if t == t else "TIR: indefinida\n")
        self.txt_analise.insert("end", f"Payback simples: {p.periodo_simples}\n")
        self.txt_analise.insert("end", f"Payback descontado: {p.periodo_descontado}\n")

    def _carregar_inicial(self) -> None:
        if os.path.exists(self.csv_path):
            ok, _ = csv_repo.carregar(self.csv_path)
            self.lancamentos = ok
            self._refresh_lanc()


class DialogLancamento(tk.Toplevel):
    def __init__(self, master: tk.Tk, on_save) -> None:
        super().__init__(master)
        self.title("Novo lançamento")
        self.on_save = on_save
        self.v = {
            "data": tk.StringVar(),
            "tipo": tk.StringVar(value="saida"),
            "escopo": tk.StringVar(value="pj"),
            "categoria": tk.StringVar(),
            "valor": tk.StringVar(value="0"),
            "descricao": tk.StringVar(),
            "fornecedor_cliente": tk.StringVar(),
            "meio_pagamento": tk.StringVar(),
        }
        rows = [
            ("Data (YYYY-MM-DD)", "data"),
            ("Tipo", "tipo"),
            ("Escopo", "escopo"),
            ("Categoria", "categoria"),
            ("Valor", "valor"),
            ("Descrição", "descricao"),
            ("Cliente/Fornecedor", "fornecedor_cliente"),
            ("Meio pagamento", "meio_pagamento"),
        ]
        for i, (label, key) in enumerate(rows):
            ttk.Label(self, text=label).grid(row=i, column=0, sticky="w", padx=6, pady=3)
            if key == "tipo":
                ttk.Combobox(self, textvariable=self.v[key], values=["entrada", "saida"], state="readonly").grid(row=i, column=1, padx=6, pady=3)
            elif key == "escopo":
                ttk.Combobox(self, textvariable=self.v[key], values=["pj", "pf"], state="readonly").grid(row=i, column=1, padx=6, pady=3)
            elif key == "categoria":
                self.cmb_cat = ttk.Combobox(self, textvariable=self.v[key], values=[c.nome for c in CATEGORIAS_MEI])
                self.cmb_cat.grid(row=i, column=1, padx=6, pady=3)
            else:
                ttk.Entry(self, textvariable=self.v[key]).grid(row=i, column=1, padx=6, pady=3)
        ttk.Button(self, text="Salvar", command=self._salvar).grid(row=len(rows), column=0, columnspan=2, pady=8)

    def _salvar(self) -> None:
        try:
            l = Lancamento(
                data=self.v["data"].get().strip(),
                tipo=self.v["tipo"].get(),  # type: ignore[arg-type]
                escopo=self.v["escopo"].get(),  # type: ignore[arg-type]
                categoria=self.v["categoria"].get().strip(),
                valor=float(self.v["valor"].get()),
                descricao=self.v["descricao"].get().strip(),
                fornecedor_cliente=self.v["fornecedor_cliente"].get().strip() or None,
                meio_pagamento=self.v["meio_pagamento"].get().strip() or None,  # type: ignore[arg-type]
            )
        except ValueError as e:
            messagebox.showerror("Erro", str(e))
            return
        self.on_save(l)
        self.destroy()


def main() -> int:
    App().mainloop()
    return 0


if __name__ == "__main__":
    sys.exit(main())
