#!/usr/bin/env python3
"""
DIESEL CFDI CONSOLIDATION - GUI

Minimal tkinter front-end for diesel.py. Pure UI glue: all CFDI parsing,
tax calculation, and file I/O logic lives in diesel.py and is imported
here, not duplicated. The CLI script keeps working standalone.

USAGE (Windows 10 / macOS / Linux):

  python diesel_gui.py

No extra dependencies: tkinter ships with the standard python.org installer.
"""

import logging
import threading
import tkinter as tk
from pathlib import Path
from tkinter import ttk, filedialog, messagebox, scrolledtext

from diesel import DieselConsolidationProcessor, setup_logging, get_base_dir


class TextHandler(logging.Handler):
    """Logging handler that appends formatted records into a Tk text widget."""

    def __init__(self, text_widget: scrolledtext.ScrolledText):
        super().__init__()
        self.text_widget = text_widget

    def emit(self, record):
        msg = self.format(record)

        def append():
            self.text_widget.configure(state='normal')
            self.text_widget.insert(tk.END, msg + "\n")
            self.text_widget.see(tk.END)
            self.text_widget.configure(state='disabled')

        self.text_widget.after(0, append)


class DieselGUI:
    def __init__(self, root: tk.Tk):
        self.root = root
        self.root.title("Diesel CFDI Consolidation")
        self.root.geometry("720x560")

        self.processor = None
        self.wb = None
        self.col_map = None
        self.output_dir = None

        self._build_form()

    def _build_form(self):
        pad = {'padx': 8, 'pady': 4}
        frame = ttk.Frame(self.root)
        frame.pack(fill=tk.X, **pad)

        # Input file
        ttk.Label(frame, text="Input XLSX file:").grid(row=0, column=0, sticky='w')
        self.input_file_var = tk.StringVar()
        ttk.Entry(frame, textvariable=self.input_file_var, width=55).grid(row=0, column=1, sticky='we')
        ttk.Button(frame, text="Browse...", command=self._browse_input).grid(row=0, column=2)

        # Output dir
        ttk.Label(frame, text="Output directory:").grid(row=1, column=0, sticky='w')
        self.output_dir_var = tk.StringVar(value="./output")
        ttk.Entry(frame, textvariable=self.output_dir_var, width=55).grid(row=1, column=1, sticky='we')
        ttk.Button(frame, text="Browse...", command=self._browse_output).grid(row=1, column=2)

        # Cuota IEPS
        ttk.Label(frame, text="Cuota IEPS (blank = default):").grid(row=2, column=0, sticky='w')
        self.cuota_ieps_var = tk.StringVar()
        ttk.Entry(frame, textvariable=self.cuota_ieps_var, width=20).grid(row=2, column=1, sticky='w')

        # Language
        ttk.Label(frame, text="Language:").grid(row=3, column=0, sticky='w')
        self.lang_var = tk.StringVar(value='es')
        ttk.Combobox(frame, textvariable=self.lang_var, values=['es', 'en'], width=10, state='readonly').grid(row=3, column=1, sticky='w')

        # Log level
        ttk.Label(frame, text="Log level:").grid(row=4, column=0, sticky='w')
        self.log_level_var = tk.StringVar(value='INFO')
        ttk.Combobox(
            frame, textvariable=self.log_level_var,
            values=['DEBUG', 'INFO', 'WARNING', 'ERROR'], width=10, state='readonly'
        ).grid(row=4, column=1, sticky='w')

        # Generate CSV
        self.generate_csv_var = tk.BooleanVar(value=False)
        ttk.Checkbutton(frame, text="Generate CSV output", variable=self.generate_csv_var).grid(
            row=5, column=1, sticky='w'
        )

        frame.columnconfigure(1, weight=1)

        # Process button + progress bar
        action_frame = ttk.Frame(self.root)
        action_frame.pack(fill=tk.X, **pad)
        self.process_button = ttk.Button(action_frame, text="Process", command=self._on_process)
        self.process_button.pack(side=tk.LEFT)
        self.progress = ttk.Progressbar(action_frame, mode='indeterminate')
        self.progress.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=8)

        # Log pane
        log_frame = ttk.LabelFrame(self.root, text="Log")
        log_frame.pack(fill=tk.BOTH, expand=True, **pad)
        self.log_widget = scrolledtext.ScrolledText(log_frame, state='disabled', wrap=tk.WORD)
        self.log_widget.pack(fill=tk.BOTH, expand=True)

    def _browse_input(self):
        path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx")])
        if path:
            self.input_file_var.set(path)

    def _browse_output(self):
        path = filedialog.askdirectory()
        if path:
            self.output_dir_var.set(path)

    def _on_process(self):
        input_file = self.input_file_var.get().strip()
        if not input_file:
            messagebox.showerror("Missing input", "Please select an input XLSX file.")
            return
        if not Path(input_file).exists():
            messagebox.showerror("File not found", f"Input file not found:\n{input_file}")
            return

        self.process_button.configure(state='disabled')
        self.log_widget.configure(state='normal')
        self.log_widget.delete('1.0', tk.END)
        self.log_widget.configure(state='disabled')
        self.progress.start(10)

        thread = threading.Thread(target=self._run_extraction, daemon=True)
        thread.start()

    def _run_extraction(self):
        try:
            output_dir = Path(self.output_dir_var.get().strip() or "./output")
            logger = setup_logging(output_dir, self.log_level_var.get())
            logger.addHandler(self._make_text_handler())

            cuota_ieps_raw = self.cuota_ieps_var.get().strip()
            cuota_ieps = float(cuota_ieps_raw) if cuota_ieps_raw else DieselConsolidationProcessor.DEFAULT_CUOTA_IEPS

            processor = DieselConsolidationProcessor(logger, self.lang_var.get())
            processor.generate_csv = self.generate_csv_var.get()

            processor.stimulus_schedule = processor.load_stimulus_schedule(str(get_base_dir() / 'estimulos.csv'))

            input_path = Path(self.input_file_var.get().strip())
            wb, col_map = processor.load_workbook(str(input_path))
            processor.process_workbook(wb, col_map)

            self.root.after(0, lambda: self._on_extraction_done(processor, output_dir, cuota_ieps))
        except Exception as e:
            self.root.after(0, lambda: self._on_error(e))

    def _make_text_handler(self) -> TextHandler:
        handler = TextHandler(self.log_widget)
        handler.setLevel(logging.DEBUG)
        handler.setFormatter(logging.Formatter('%(levelname)-8s | %(message)s'))
        return handler

    def _on_extraction_done(self, processor, output_dir: Path, cuota_ieps: float):
        self.progress.stop()
        self.process_button.configure(state='normal')

        if not processor.invoices:
            messagebox.showinfo("No diesel items", processor.t['no_items_found'])
            return

        totals = processor.get_totals()
        summary = (
            f"Invoices found: {totals['invoices_found']}\n"
            f"Total diesel line items: {totals['total_items']}\n"
            f"Total liters: {totals['litros']:.2f} L\n"
            f"Subtotal: ${totals['importe']:,.2f}\n"
            f"IVA (16%): ${totals['iva']:,.2f}\n"
            f"TOTAL: ${totals['total']:,.2f}\n\n"
            f"Proceed with writing output files to {output_dir}?"
        )

        if not messagebox.askyesno("Confirm output", summary):
            processor.logger.info("User declined to proceed (GUI)")
            return

        try:
            self._write_outputs(processor, output_dir, cuota_ieps)
        except Exception as e:
            self._on_error(e)

    def _write_outputs(self, processor, output_dir: Path, cuota_ieps: float):
        from datetime import datetime

        output_dir.mkdir(parents=True, exist_ok=True)
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename_base = f"{processor.rfc_receptor}_{processor.anio}_{processor.mes:02d}_{timestamp}"

        xlsx_path = output_dir / f"{filename_base}.xlsx"
        processor.write_xlsx(xlsx_path, cuota_ieps)

        written = [str(xlsx_path)]
        if processor.generate_csv:
            csv_path = output_dir / f"{filename_base}.csv"
            processor.write_csv(csv_path)
            written.append(str(csv_path))

        processor.logger.info("Consolidation completed successfully (GUI)")
        messagebox.showinfo("Files written", "Output files written successfully:\n\n" + "\n".join(written))

    def _on_error(self, error: Exception):
        self.progress.stop()
        self.process_button.configure(state='normal')
        messagebox.showerror("Error", str(error))


def main():
    root = tk.Tk()
    DieselGUI(root)
    root.mainloop()


if __name__ == '__main__':
    main()
