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

from .profile_manager import ProfileManager
from ..config import profiles as profiles_cfg
from ..config import settings as app_settings
from ..core.differ import BaselineManager, Differ


class TopBar(ttk.Frame):
    """Shared top bar containing profile selection and folder selection.

    The TopBar exposes `path_var` (StringVar) and `current_profile` dict
    that other tabs can read to apply profile-specific settings.
    """

    def __init__(self, parent, *args, **kwargs):
        """Initialize the TopBar.

        Args:
            parent: The parent Tk widget where the top bar will be placed.
        """
        super().__init__(parent, *args, **kwargs)

        self.path_var = tk.StringVar()
        self.current_profile = None

        # Profiles combobox
        ttk.Label(self, text="Profile:").grid(row=0, column=0, sticky="w", padx=(8, 4), pady=8)
        self.profile_var = tk.StringVar()
        self.profile_cb = ttk.Combobox(self, textvariable=self.profile_var, state="readonly")
        self._load_profiles()
        self.profile_cb.grid(row=0, column=1, sticky="ew", padx=(0, 6))
        self.profile_cb.bind("<<ComboboxSelected>>", self._on_profile_selected)

        manage_btn = ttk.Button(self, text="Manage...", command=self._open_manager)
        manage_btn.grid(row=0, column=2, sticky="w", padx=(4, 4))
        settings_btn = ttk.Button(self, text="Settings...", command=self._open_settings)
        settings_btn.grid(row=0, column=3, sticky="w", padx=(4, 4))
        # Note: Differing action moved to the main Actions bar in the GUI
        # Info area: project type above folder label (read-only, driven by profile)
        info = ttk.Frame(self)
        info.grid(row=0, column=4, columnspan=2, sticky="ew", padx=(8, 8))
        ttk.Label(info, text="Type:").grid(row=0, column=0, sticky="w")
        self.project_type_var = tk.StringVar(value="-")
        ttk.Label(info, textvariable=self.project_type_var).grid(row=0, column=1, sticky="w", padx=(6, 0))
        # Folder display removed: profiles can contain multiple paths now

        self.columnconfigure(1, weight=0)
        self.columnconfigure(4, weight=1)

    def _load_profiles(self):
        profs = profiles_cfg.load_profiles()
        names = [p.get("name") for p in profs]
        self.profile_cb["values"] = names

    def _on_profile_selected(self, _evt=None):
        name = self.profile_var.get()
        if not name:
            return
        pr = profiles_cfg.find_profile(name)
        if not pr:
            return
        self.current_profile = pr
        # Set folder and optionally other UI hints
        # prefer new 'paths' list (no legacy compatibility)
        paths = pr.get("paths") or []
        first = paths[0] if paths else ""
        self.path_var.set(first)
        # determine a simple project type hint from profile languages
        langs = pr.get("languages", []) or []
        ptype = ""
        if "Python" in langs:
            ptype = "Python"
        elif "C++" in langs or "C" in langs:
            ptype = "C/C++"
        elif "Java" in langs:
            ptype = "Java"
        elif len(langs) == 1:
            ptype = langs[0]
        elif langs:
            ptype = ",".join(langs)
        else:
            ptype = "Unknown"
        self.project_type_var.set(ptype)

    def _open_manager(self):
        def _refresh():
            self._load_profiles()
        pm = ProfileManager(self.master, on_change=_refresh)
        pm.grab_set()

    def _open_settings(self):
        try:
            from .settings_dialog import SettingsDialog
            dlg = SettingsDialog(self.master)
            dlg.grab_set()
        except Exception as e:
            try:
                messagebox.showerror("Settings", f"Failed to open settings: {e}")
            except Exception:
                pass

    def browse(self) -> None:
        """Open a directory selection dialog and update `path_var`.

        The selected path is stored as an absolute string in `path_var`.
        """
        directory = filedialog.askdirectory()
        if directory:
            self.path_var.set(str(Path(directory)))

    def _on_differ(self):
        proj_path = self.path_var.get()
        if not proj_path:
            messagebox.showerror("Differing", "No project path selected.")
            return

        bm = BaselineManager(proj_path)

        baselines = bm.list_baselines()
        if not baselines:
            # no baseline: ask to create
            create = messagebox.askyesno("Differing", "No baseline found for this project. Create baseline now?")
            if not create:
                return

            try:
                # Create baseline from the selected folder (snapshot)
                profile_name = self.current_profile.get('name') if self.current_profile else None
                baseline_id = bm.create_baseline_from_dir(proj_path, baseline_id=None, snapshot=True, compute_sha1=True, ignore_patterns=None, profile_name=profile_name, max_keep=5)
            except Exception as e:
                messagebox.showerror("Differing", f"Failed to create baseline: {e}")
                return
            messagebox.showinfo("Differing", f"Baseline created: {baseline_id}")
            return

        # If baselines exist, pick the most recent by name (lexicographic)
        latest = sorted(baselines)[-1]
        try:
            metadata = bm.load_metadata(latest)
        except Exception as e:
            messagebox.showerror("Differing", f"Failed to load baseline metadata: {e}")
            return

        # Run diff in background thread
        def _run_diff():
            btn = None
            try:
                # respect profile ignore patterns when diffing
                pr = self.current_profile
                ignore_patterns = pr.get('ignore', []) if pr else None
                d = Differ(metadata, proj_path, ignore_patterns=ignore_patterns)
                result = d.diff()
                total = result.get("total", {})
                msg = f"Diff completed. Added: {total.get('added',0)}, Deleted: {total.get('deleted',0)}, Modified: {total.get('modified',0)}"
                messagebox.showinfo("Differing", msg)
                # save current state as a new baseline so it's available next time
                try:
                    profile_name = self.current_profile.get('name') if self.current_profile else None
                    bm2 = BaselineManager(proj_path)
                    mk = app_settings.get_max_keep()
                    bm2.create_baseline_from_dir(proj_path, baseline_id=None, snapshot=True, compute_sha1=True, ignore_patterns=ignore_patterns, profile_name=profile_name, max_keep=mk)
                except Exception:
                    pass
            except Exception as e:
                messagebox.showerror("Differing", f"Diff failed: {e}")

        t = threading.Thread(target=_run_diff, daemon=True)
        t.start()
