import os
import sys
import time
import tkinter as tk
from tkinter import ttk, messagebox
from datetime import timedelta

from engine import AutoKeyEngine
from storage import ProfileStore, Profile

try:
    from PIL import Image, ImageTk
except Exception:
    Image = None
    ImageTk = None

APP_AUTHOR = "AG WebDev"
APP_COPYRIGHT = "© 2025 AG WebDev. Freeware — No Resale."
APP_LICENSE_HINT = "Use is free. Selling/redistribution/modification is not allowed."


def resource_path(relative_path: str) -> str:
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)


def clamp_int(s: str, default: int, mn: int = 1, mx: int = 999999) -> int:
    try:
        v = int(float(str(s).strip()))
        if v < mn:
            return mn
        if v > mx:
            return mx
        return v
    except Exception:
        return default


def parse_keys_list(text: str):
    raw = (text or "").strip()
    if not raw:
        return []
    parts = [p.strip().lower() for p in raw.split(",")]
    return [p for p in parts if p]


class AppUI(tk.Tk):
    def __init__(self):
        super().__init__()

        # Theme (AG WebDev-ish)
        self.accent = "#d51920"
        self.accent_hover = "#b3151b"
        self.bg = "#0f0f10"
        self.surface = "#141416"
        self.card = "#1b1c1f"
        self.border = "#2a2b31"
        self.text = "#f4f4f5"
        self.muted = "#b0b2b8"

        self.running_green = "#1f8b4c"
        self.stopped_gray = "#3a3a3a"

        self.title("AutoKey Premium — AG WebDev")
        self.geometry("1040x740")
        self.minsize(920, 620)
        self.configure(bg=self.bg)

        try:
            self.iconbitmap(resource_path("assets/icon.ico"))
        except Exception:
            pass

        self.store = ProfileStore()
        self.active_profile_name = tk.StringVar(value=self.store.get_active_name())

        # UI Vars (bind to profile)
        self.keys_var = tk.StringVar()
        self.stop_var = tk.StringVar()
        self.mode_var = tk.StringVar(value="fixed")

        self.fixed_var = tk.StringVar()
        self.rmin_var = tk.StringVar()
        self.rmax_var = tk.StringVar()

        self.smart_base_var = tk.StringVar()
        self.smart_jitter_var = tk.StringVar()

        self.auto_start_var = tk.BooleanVar(value=False)
        self.status_var = tk.StringVar(value="STOPPED")

        self.presses_var = tk.StringVar(value="0")
        self.runtime_var = tk.StringVar(value="00:00:00")

        self._setup_styles()
        self._build_ui()

        self.engine = AutoKeyEngine(
            log_fn=self.append_log,
            status_fn=self.set_status,
            stats_fn=self.update_stats,
        )

        self.protocol("WM_DELETE_WINDOW", self.on_close)

        self.load_profile(self.store.get_active_name())

        # Watermark / license hint in log on launch
        self.append_log(f"AutoKey Premium — {APP_COPYRIGHT}", "info")
        self.append_log(APP_LICENSE_HINT, "info")

        # Auto-start if enabled (wait 900ms so UI is ready)
        self.after(900, self._maybe_autostart)

    # -------------------- UI / Theme --------------------

    def _setup_styles(self):
        s = ttk.Style(self)
        s.theme_use("clam")

        s.configure("TLabel", background=self.bg, foreground=self.text, font=("Segoe UI", 10))
        s.configure("Muted.TLabel", background=self.bg, foreground=self.muted, font=("Segoe UI", 10))

        s.configure("Card.TFrame", background=self.card)

        s.configure("CardTitle.TLabel", background=self.card, foreground=self.text, font=("Segoe UI", 12, "bold"))
        s.configure("CardSub.TLabel", background=self.card, foreground=self.muted, font=("Segoe UI", 10))

        s.configure(
            "Modern.TEntry",
            fieldbackground="#111113",
            foreground=self.text,
            insertcolor=self.text,
            bordercolor=self.border,
            lightcolor=self.border,
            darkcolor=self.border,
            padding=10,
            relief="flat",
        )

        s.configure(
            "Primary.TButton",
            background=self.accent,
            foreground="white",
            font=("Segoe UI", 11, "bold"),
            padding=(20, 14),
            borderwidth=0,
            focusthickness=0,
        )
        s.map(
            "Primary.TButton",
            background=[("active", self.accent_hover), ("disabled", "#6b1a1d")],
            foreground=[("disabled", "#cccccc")],
        )

        s.configure(
            "Ghost.TButton",
            background=self.card,
            foreground=self.text,
            font=("Segoe UI", 11),
            padding=(20, 14),
            borderwidth=1,
            relief="solid",
        )
        s.map(
            "Ghost.TButton",
            background=[("active", "#2a2b31"), ("disabled", "#1a1b1f")],
            foreground=[("disabled", "#7a7a80")],
        )

        s.configure(
            "Subtle.TButton",
            background="#23242a",
            foreground=self.text,
            font=("Segoe UI", 10),
            padding=(16, 12),
            borderwidth=0,
        )
        s.map(
            "Subtle.TButton",
            background=[("active", "#2b2c33"), ("disabled", "#1a1b1f")],
            foreground=[("disabled", "#7a7a80")],
        )

        s.configure("Modern.TCombobox", padding=8)

        self.style = s

    def _build_ui(self):
        # Header
        header = tk.Frame(self, bg=self.surface, height=82, highlightbackground=self.border, highlightthickness=1)
        header.pack(fill="x")
        header.pack_propagate(False)

        left = tk.Frame(header, bg=self.surface)
        left.pack(side="left", padx=20)

        if Image and ImageTk:
            try:
                logo_path = resource_path("assets/logo.png")
                img = Image.open(logo_path).convert("RGBA").resize((40, 40))
                self.logo_img = ImageTk.PhotoImage(img)
                tk.Label(left, image=self.logo_img, bg=self.surface).pack(side="left", padx=(0, 10))
            except Exception:
                pass

        tbox = tk.Frame(left, bg=self.surface)
        tbox.pack(side="left")

        tk.Label(tbox, text="AUTOKEY PREMIUM", font=("Segoe UI", 16, "bold"), fg=self.text, bg=self.surface).pack(anchor="w")
        tk.Label(tbox, text=" Automation Tool", font=("Segoe UI", 10), fg=self.muted, bg=self.surface).pack(anchor="w")

        right = tk.Frame(header, bg=self.surface)
        right.pack(side="right", padx=20)

        # Copyright label (header)
        tk.Label(
            right,
            text=APP_COPYRIGHT,
            font=("Segoe UI", 9),
            fg=self.muted,
            bg=self.surface,
        ).pack(side="left", padx=(0, 12))

        # Status pill
        self.status_pill = tk.Frame(right, bg=self.stopped_gray, highlightbackground=self.border, highlightthickness=1)
        self.status_pill.pack(side="left")

        self.status_dot = tk.Canvas(self.status_pill, width=12, height=12, bg=self.stopped_gray, highlightthickness=0)
        self.status_dot.pack(side="left", padx=(12, 8), pady=10)
        self.dot_id = self.status_dot.create_oval(2, 2, 10, 10, fill="#b0b2b8", outline="")

        self.status_label = tk.Label(
            self.status_pill,
            textvariable=self.status_var,
            font=("Segoe UI", 10, "bold"),
            fg="white",
            bg=self.stopped_gray,
            padx=12,
            pady=8,
        )
        self.status_label.pack(side="left", padx=(0, 12))

        # Main container
        main = tk.Frame(self, bg=self.bg)
        main.pack(fill="both", expand=True, padx=20, pady=20)
        main.grid_columnconfigure(0, weight=1)
        main.grid_columnconfigure(1, weight=1)
        main.grid_rowconfigure(1, weight=1)

        # Left card: Profiles + Settings
        left_card = ttk.Frame(main, style="Card.TFrame", padding=20)
        left_card.grid(row=0, column=0, sticky="nsew", padx=(0, 10), pady=(0, 15))

        ttk.Label(left_card, text="Profiles & Presets", style="CardTitle.TLabel").grid(row=0, column=0, sticky="w")
        ttk.Label(left_card, text="Save, load and manage automation setups", style="CardSub.TLabel").grid(row=1, column=0, sticky="w", pady=(2, 18))

        # Profile row
        prof_row = tk.Frame(left_card, bg=self.card)
        prof_row.grid(row=2, column=0, sticky="ew")
        prof_row.grid_columnconfigure(1, weight=1)

        tk.Label(prof_row, text="Active profile", font=("Segoe UI", 10, "bold"), fg=self.muted, bg=self.card).grid(row=0, column=0, sticky="w", padx=(0, 10))

        self.profile_combo = ttk.Combobox(
            prof_row,
            textvariable=self.active_profile_name,
            values=self.store.list_profiles(),
            state="readonly",
            style="Modern.TCombobox",
        )
        self.profile_combo.grid(row=0, column=1, sticky="ew")
        self.profile_combo.bind("<<ComboboxSelected>>", lambda e: self.on_profile_selected())

        btns = tk.Frame(left_card, bg=self.card)
        btns.grid(row=3, column=0, sticky="ew", pady=(12, 0))
        btns.grid_columnconfigure(0, weight=1)
        btns.grid_columnconfigure(1, weight=1)
        btns.grid_columnconfigure(2, weight=1)

        self.save_profile_btn = ttk.Button(btns, text="💾 SAVE", style="Subtle.TButton", command=self.on_save_profile)
        self.save_profile_btn.grid(row=0, column=0, sticky="ew", padx=(0, 10))

        self.save_as_btn = ttk.Button(btns, text="🧩 SAVE AS…", style="Subtle.TButton", command=self.on_save_as)
        self.save_as_btn.grid(row=0, column=1, sticky="ew", padx=(0, 10))

        self.delete_btn = ttk.Button(btns, text="🗑 DELETE", style="Subtle.TButton", command=self.on_delete_profile)
        self.delete_btn.grid(row=0, column=2, sticky="ew")

        # Settings form
        ttk.Separator(left_card).grid(row=4, column=0, sticky="ew", pady=16)

        ttk.Label(left_card, text="Automation Settings", style="CardTitle.TLabel").grid(row=5, column=0, sticky="w")
        ttk.Label(left_card, text="Multiple keys, interval modes and auto-start", style="CardSub.TLabel").grid(row=6, column=0, sticky="w", pady=(2, 18))

        form = tk.Frame(left_card, bg=self.card)
        form.grid(row=7, column=0, sticky="ew")
        form.grid_columnconfigure(0, weight=1)

        # Keys
        tk.Label(form, text="Keys (comma separated)", font=("Segoe UI", 10, "bold"), fg=self.muted, bg=self.card).grid(row=0, column=0, sticky="w", pady=(0, 6))
        self.keys_entry = ttk.Entry(form, textvariable=self.keys_var, style="Modern.TEntry", font=("Segoe UI", 11))
        self.keys_entry.grid(row=1, column=0, sticky="ew", pady=(0, 14))

        # Stop
        tk.Label(form, text="Stop key", font=("Segoe UI", 10, "bold"), fg=self.muted, bg=self.card).grid(row=2, column=0, sticky="w", pady=(0, 6))
        self.stop_entry = ttk.Entry(form, textvariable=self.stop_var, style="Modern.TEntry", font=("Segoe UI", 11))
        self.stop_entry.grid(row=3, column=0, sticky="ew", pady=(0, 14))

        # Interval mode
        rowm = tk.Frame(form, bg=self.card)
        rowm.grid(row=4, column=0, sticky="ew")
        rowm.grid_columnconfigure(1, weight=1)

        tk.Label(rowm, text="Interval mode", font=("Segoe UI", 10, "bold"), fg=self.muted, bg=self.card).grid(row=0, column=0, sticky="w", padx=(0, 10))
        self.mode_combo = ttk.Combobox(rowm, textvariable=self.mode_var, values=["fixed", "random", "smart"], state="readonly", style="Modern.TCombobox")
        self.mode_combo.grid(row=0, column=1, sticky="ew")
        self.mode_combo.bind("<<ComboboxSelected>>", lambda e: self._refresh_mode_fields())

        # Mode fields container
        self.mode_fields = tk.Frame(form, bg=self.card)
        self.mode_fields.grid(row=5, column=0, sticky="ew", pady=(12, 0))
        self.mode_fields.grid_columnconfigure(0, weight=1)
        self.mode_fields.grid_columnconfigure(1, weight=1)

        # Fixed
        self.fixed_label = tk.Label(self.mode_fields, text="Fixed interval (s)", font=("Segoe UI", 10, "bold"),
                                    fg=self.muted, bg=self.card)
        self.fixed_entry = ttk.Entry(self.mode_fields, textvariable=self.fixed_var, style="Modern.TEntry", font=("Segoe UI", 11))

        # Random
        self.rmin_label = tk.Label(self.mode_fields, text="Min (s)", font=("Segoe UI", 10, "bold"), fg=self.muted, bg=self.card)
        self.rmin_entry = ttk.Entry(self.mode_fields, textvariable=self.rmin_var, style="Modern.TEntry", font=("Segoe UI", 11))

        self.rmax_label = tk.Label(self.mode_fields, text="Max (s)", font=("Segoe UI", 10, "bold"), fg=self.muted, bg=self.card)
        self.rmax_entry = ttk.Entry(self.mode_fields, textvariable=self.rmax_var, style="Modern.TEntry", font=("Segoe UI", 11))

        # Smart
        self.smart_base_label = tk.Label(self.mode_fields, text="Smart base (s)", font=("Segoe UI", 10, "bold"), fg=self.muted, bg=self.card)
        self.smart_base_entry = ttk.Entry(self.mode_fields, textvariable=self.smart_base_var, style="Modern.TEntry", font=("Segoe UI", 11))

        self.smart_jit_label = tk.Label(self.mode_fields, text="Jitter (%)", font=("Segoe UI", 10, "bold"), fg=self.muted, bg=self.card)
        self.smart_jit_entry = ttk.Entry(self.mode_fields, textvariable=self.smart_jitter_var, style="Modern.TEntry", font=("Segoe UI", 11))

        # Auto-start checkbox
        self.autostart_chk = tk.Checkbutton(
            form,
            text="Auto start this profile on launch",
            variable=self.auto_start_var,
            onvalue=True,
            offvalue=False,
            bg=self.card,
            fg=self.text,
            activebackground=self.card,
            activeforeground=self.text,
            selectcolor=self.card,
            font=("Segoe UI", 10),
        )
        self.autostart_chk.grid(row=6, column=0, sticky="w", pady=(16, 0))

        hint = tk.Label(form,
                        text="Tip: keys example: e, space, f1 | stop key example: f12",
                        font=("Segoe UI", 9),
                        fg="#7c7f88",
                        bg=self.card)
        hint.grid(row=7, column=0, sticky="w", pady=(10, 0))

        # Right card: Controls + Stats
        right_card = ttk.Frame(main, style="Card.TFrame", padding=20)
        right_card.grid(row=0, column=1, sticky="nsew", padx=(10, 0), pady=(0, 15))

        ttk.Label(right_card, text="Controls", style="CardTitle.TLabel").grid(row=0, column=0, sticky="w")
        ttk.Label(right_card, text="Start/stop automation + testing tools", style="CardSub.TLabel").grid(row=1, column=0, sticky="w", pady=(2, 18))

        grid = tk.Frame(right_card, bg=self.card)
        grid.grid(row=2, column=0, sticky="ew")
        grid.grid_columnconfigure(0, weight=1)
        grid.grid_columnconfigure(1, weight=1)

        self.start_btn = ttk.Button(grid, text="▶ START", style="Primary.TButton", command=self.on_start)
        self.start_btn.grid(row=0, column=0, sticky="nsew", padx=(0, 10), pady=(0, 10))

        self.stop_btn = ttk.Button(grid, text="⏹ STOP", style="Ghost.TButton", command=self.on_stop, state="disabled")
        self.stop_btn.grid(row=0, column=1, sticky="nsew", pady=(0, 10))

        self.test_btn = ttk.Button(grid, text="🔧 TEST", style="Subtle.TButton", command=self.on_test)
        self.test_btn.grid(row=1, column=0, sticky="nsew", padx=(0, 10))

        self.clear_btn = ttk.Button(grid, text="🗑 CLEAR LOG", style="Subtle.TButton", command=self.on_clear)
        self.clear_btn.grid(row=1, column=1, sticky="nsew")

        # License button (opens LICENSE.txt)
        self.license_btn = ttk.Button(grid, text="📄 LICENSE", style="Subtle.TButton", command=self.show_license)
        self.license_btn.grid(row=2, column=0, columnspan=2, sticky="nsew", pady=(10, 0))

        # Stats block
        stats = tk.Frame(right_card, bg=self.card)
        stats.grid(row=3, column=0, sticky="ew", pady=(18, 0))

        tk.Label(stats, text="📊 Statistics", font=("Segoe UI", 11, "bold"), fg=self.text, bg=self.card).pack(anchor="w", pady=(0, 10))

        tk.Label(stats, text="Presses", font=("Segoe UI", 10), fg=self.muted, bg=self.card).pack(anchor="w")
        tk.Label(stats, textvariable=self.presses_var, font=("Segoe UI", 14, "bold"), fg=self.text, bg=self.card).pack(anchor="w", pady=(0, 10))

        tk.Label(stats, text="Runtime", font=("Segoe UI", 10), fg=self.muted, bg=self.card).pack(anchor="w")
        tk.Label(stats, textvariable=self.runtime_var, font=("Segoe UI", 14, "bold"), fg=self.text, bg=self.card).pack(anchor="w")

        # Log card (bottom full)
        log_card = ttk.Frame(main, style="Card.TFrame", padding=20)
        log_card.grid(row=1, column=0, columnspan=2, sticky="nsew", pady=(15, 0))

        header = tk.Frame(log_card, bg=self.card)
        header.pack(fill="x", pady=(0, 15))
        ttk.Label(header, text="Activity Log", style="CardTitle.TLabel").pack(side="left")
        tk.Label(header, text="Professional real-time logging", font=("Segoe UI", 10), fg=self.muted, bg=self.card).pack(side="right")

        frame = tk.Frame(log_card, bg=self.border, bd=1, relief="solid")
        frame.pack(fill="both", expand=True)

        sb = ttk.Scrollbar(frame)
        sb.pack(side="right", fill="y")

        self.log_text = tk.Text(
            frame,
            wrap="word",
            bg="#101012",
            fg=self.text,
            insertbackground=self.text,
            relief="flat",
            bd=0,
            font=("Cascadia Code", 10),
            yscrollcommand=sb.set,
        )
        self.log_text.pack(fill="both", expand=True, padx=1, pady=1)
        sb.config(command=self.log_text.yview)

        self.log_text.tag_config("info", foreground="#b0b2b8")
        self.log_text.tag_config("success", foreground="#1f8b4c")
        self.log_text.tag_config("warning", foreground="#f39c12")
        self.log_text.tag_config("error", foreground="#e74c3c")
        self.log_text.tag_config("highlight", foreground="#ff2d3a")

        self._refresh_mode_fields()

    # -------------------- License UI --------------------

    def show_license(self):
        try:
            path = resource_path("LICENSE.txt")
            with open(path, "r", encoding="utf-8") as f:
                txt = f.read()
        except Exception as e:
            messagebox.showerror("License", f"Could not open LICENSE.txt\n\n{e}")
            return

        win = tk.Toplevel(self)
        win.title("License")
        win.configure(bg=self.bg)
        win.geometry("720x520")
        win.minsize(520, 360)
        win.grab_set()

        box = tk.Text(
            win,
            wrap="word",
            bg="#101012",
            fg=self.text,
            insertbackground=self.text,
            relief="flat",
            bd=0,
            font=("Cascadia Code", 10),
        )
        box.pack(fill="both", expand=True, padx=14, pady=14)
        box.insert("1.0", txt)
        box.config(state="disabled")

    # -------------------- Log / Status / Stats --------------------

    def append_log(self, msg: str, level="info"):
        def _a():
            self.log_text.insert("end", msg + "\n", level)
            self.log_text.see("end")
        self.after(0, _a)

    def set_status(self, status: str):
        def _s():
            self.status_var.set(status)
            if status == "RUNNING":
                self.status_pill.config(bg=self.running_green)
                self.status_label.config(bg=self.running_green)
                self.status_dot.config(bg=self.running_green)
                self.status_dot.itemconfig(self.dot_id, fill="#c9ffd9")

                self.start_btn.config(state="disabled")
                self.stop_btn.config(state="normal")

                self._lock_inputs(True)
                self.append_log("=== Automation Started ===", "success")
            else:
                self.status_pill.config(bg=self.stopped_gray)
                self.status_label.config(bg=self.stopped_gray)
                self.status_dot.config(bg=self.stopped_gray)
                self.status_dot.itemconfig(self.dot_id, fill="#b0b2b8")

                self.start_btn.config(state="normal")
                self.stop_btn.config(state="disabled")

                self._lock_inputs(False)
                self.append_log("=== Automation Stopped ===", "info")
        self.after(0, _s)

    def update_stats(self, presses: int, runtime_sec: int):
        def _u():
            self.presses_var.set(str(presses))
            self.runtime_var.set(str(timedelta(seconds=int(runtime_sec))))
        self.after(0, _u)

    def _lock_inputs(self, lock: bool):
        st = "disabled" if lock else "normal"
        self.keys_entry.config(state=st)
        self.stop_entry.config(state=st)
        self.profile_combo.config(state="disabled" if lock else "readonly")
        self.mode_combo.config(state="disabled" if lock else "readonly")

        for w in [
            self.fixed_entry, self.rmin_entry, self.rmax_entry,
            self.smart_base_entry, self.smart_jit_entry
        ]:
            try:
                w.config(state=st)
            except Exception:
                pass

        self.save_profile_btn.config(state="disabled" if lock else "normal")
        self.save_as_btn.config(state="disabled" if lock else "normal")
        self.delete_btn.config(state="disabled" if lock else "normal")
        self.autostart_chk.config(state="disabled" if lock else "normal")

    # -------------------- Profiles --------------------

    def on_profile_selected(self):
        name = self.active_profile_name.get()
        self.store.set_active(name)
        self.load_profile(name)
        self.append_log(f"Active profile changed to '{name}'", "highlight")

    def load_profile(self, name: str):
        p = self.store.get_profile(name)

        self.keys_var.set(", ".join(p.keys or ["e"]))
        self.stop_var.set(p.stop_key or "f12")
        self.mode_var.set(p.interval_mode or "fixed")

        self.fixed_var.set(str(p.interval_fixed))
        self.rmin_var.set(str(p.interval_min))
        self.rmax_var.set(str(p.interval_max))
        self.smart_base_var.set(str(p.smart_base))
        self.smart_jitter_var.set(str(p.smart_jitter_pct))
        self.auto_start_var.set(bool(p.auto_start))

        self._refresh_mode_fields()
        self._refresh_profile_combo()

    def _refresh_profile_combo(self):
        self.profile_combo["values"] = self.store.list_profiles()

    def _collect_profile_from_ui(self, name: str) -> Profile:
        keys = parse_keys_list(self.keys_var.get())
        if not keys:
            raise ValueError("Keys list cannot be empty. Example: e, space, f1")

        stop = (self.stop_var.get() or "").strip().lower()
        if not stop:
            raise ValueError("Stop key cannot be empty. Example: f12")

        mode = self.mode_var.get().strip().lower()
        if mode not in ("fixed", "random", "smart"):
            mode = "fixed"

        p = Profile(name=name)
        p.keys = keys
        p.stop_key = stop
        p.interval_mode = mode
        p.auto_start = bool(self.auto_start_var.get())

        p.interval_fixed = clamp_int(self.fixed_var.get(), 13, 1, 999999)

        p.interval_min = clamp_int(self.rmin_var.get(), 10, 1, 999999)
        p.interval_max = clamp_int(self.rmax_var.get(), 18, p.interval_min, 999999)

        p.smart_base = clamp_int(self.smart_base_var.get(), 13, 1, 999999)
        p.smart_jitter_pct = clamp_int(self.smart_jitter_var.get(), 12, 0, 80)

        return p

    def on_save_profile(self):
        if self.engine.is_running():
            return
        name = self.active_profile_name.get()
        try:
            p = self._collect_profile_from_ui(name)
            self.store.upsert_profile(p)
            self.append_log(f"Profile '{name}' saved", "success")
            self._refresh_profile_combo()
        except Exception as e:
            messagebox.showerror("Save failed", str(e))
            self.append_log(f"Save failed: {e}", "error")

    def on_save_as(self):
        if self.engine.is_running():
            return
        name = self._prompt_text("Save As", "Enter new profile name:")
        if not name:
            return
        name = name.strip()
        if not name:
            return

        try:
            p = self._collect_profile_from_ui(name)
            self.store.upsert_profile(p)
            self.store.set_active(name)
            self.active_profile_name.set(name)
            self._refresh_profile_combo()
            self.append_log(f"Profile saved as '{name}'", "success")
        except Exception as e:
            messagebox.showerror("Save As failed", str(e))
            self.append_log(f"Save As failed: {e}", "error")

    def on_delete_profile(self):
        if self.engine.is_running():
            return
        name = self.active_profile_name.get()
        if name == "Default":
            messagebox.showinfo("Not allowed", "Default profile cannot be deleted.")
            return

        if not messagebox.askyesno("Delete profile", f"Delete '{name}'?"):
            return

        self.store.delete_profile(name)
        new_active = self.store.get_active_name()
        self.active_profile_name.set(new_active)
        self.load_profile(new_active)
        self._refresh_profile_combo()
        self.append_log(f"Profile '{name}' deleted", "warning")

    def _prompt_text(self, title: str, label: str) -> str:
        win = tk.Toplevel(self)
        win.title(title)
        win.configure(bg=self.bg)
        win.resizable(False, False)
        win.grab_set()

        tk.Label(win, text=label, font=("Segoe UI", 10), fg=self.text, bg=self.bg).pack(anchor="w", padx=16, pady=(14, 6))
        v = tk.StringVar()
        ent = ttk.Entry(win, textvariable=v, style="Modern.TEntry", font=("Segoe UI", 11))
        ent.pack(fill="x", padx=16)
        ent.focus_set()

        out = {"val": ""}

        def ok():
            out["val"] = v.get()
            win.destroy()

        def cancel():
            win.destroy()

        row = tk.Frame(win, bg=self.bg)
        row.pack(fill="x", padx=16, pady=14)
        ttk.Button(row, text="Cancel", style="Ghost.TButton", command=cancel).pack(side="right")
        ttk.Button(row, text="OK", style="Primary.TButton", command=ok).pack(side="right", padx=(0, 10))

        win.bind("<Return>", lambda e: ok())
        win.bind("<Escape>", lambda e: cancel())

        self.wait_window(win)
        return out["val"]

    # -------------------- Interval UI switching --------------------

    def _refresh_mode_fields(self):
        # clear
        for w in self.mode_fields.winfo_children():
            w.grid_forget()

        mode = self.mode_var.get()

        if mode == "fixed":
            self.fixed_label.grid(row=0, column=0, sticky="w", pady=(0, 6))
            self.fixed_entry.grid(row=1, column=0, sticky="ew")
        elif mode == "random":
            self.rmin_label.grid(row=0, column=0, sticky="w", pady=(0, 6))
            self.rmax_label.grid(row=0, column=1, sticky="w", pady=(0, 6))
            self.rmin_entry.grid(row=1, column=0, sticky="ew", padx=(0, 10))
            self.rmax_entry.grid(row=1, column=1, sticky="ew")
        else:  # smart
            self.smart_base_label.grid(row=0, column=0, sticky="w", pady=(0, 6))
            self.smart_jit_label.grid(row=0, column=1, sticky="w", pady=(0, 6))
            self.smart_base_entry.grid(row=1, column=0, sticky="ew", padx=(0, 10))
            self.smart_jit_entry.grid(row=1, column=1, sticky="ew")

    # -------------------- Controls --------------------

    def _apply_engine_settings_from_ui(self):
        keys = parse_keys_list(self.keys_var.get())
        if not keys:
            raise ValueError("Keys list cannot be empty. Example: e, space, f1")

        stop = (self.stop_var.get() or "").strip().lower()
        if not stop:
            raise ValueError("Stop key cannot be empty. Example: f12")

        mode = self.mode_var.get().strip().lower()
        if mode not in ("fixed", "random", "smart"):
            mode = "fixed"

        self.engine.keys = keys
        self.engine.stop_key = stop
        self.engine.interval_mode = mode

        self.engine.interval_fixed = clamp_int(self.fixed_var.get(), 13, 1, 999999)
        self.engine.interval_min = clamp_int(self.rmin_var.get(), 10, 1, 999999)
        self.engine.interval_max = clamp_int(self.rmax_var.get(), 18, self.engine.interval_min, 999999)

        self.engine.smart_base = clamp_int(self.smart_base_var.get(), 13, 1, 999999)
        self.engine.smart_jitter_pct = clamp_int(self.smart_jitter_var.get(), 12, 0, 80)

    def on_start(self):
        try:
            # save current profile changes automatically before start (PRO feel)
            self.on_save_profile()

            self._apply_engine_settings_from_ui()

            self.append_log("Settings applied:", "highlight")
            self.append_log(f"  • Keys: {', '.join(self.engine.keys)}", "info")
            self.append_log(f"  • Stop: {self.engine.stop_key.upper()}", "warning")
            self.append_log(f"  • Mode: {self.engine.interval_mode}", "info")
            if self.engine.interval_mode == "fixed":
                self.append_log(f"  • Fixed: {self.engine.interval_fixed}s", "info")
            elif self.engine.interval_mode == "random":
                self.append_log(f"  • Random: {self.engine.interval_min}-{self.engine.interval_max}s", "info")
            else:
                self.append_log(f"  • Smart: base {self.engine.smart_base}s ± {self.engine.smart_jitter_pct}%", "info")

            self.engine.start()
        except Exception as e:
            messagebox.showerror("Start failed", str(e))
            self.append_log(f"Start failed: {e}", "error")

    def on_stop(self):
        self.engine.stop()

    def on_test(self):
        # Just press first key once (quick verification)
        try:
            self._apply_engine_settings_from_ui()
            k = self.engine.keys[0]
            import keyboard as kb
            kb.press(k)
            time.sleep(0.03)
            kb.release(k)
            self.append_log(f"Test pressed '{k}'", "success")
        except Exception as e:
            self.append_log(f"Test failed: {e}", "error")

    def on_clear(self):
        self.log_text.delete("1.0", tk.END)
        self.append_log("Log cleared", "info")

    # -------------------- Auto start --------------------

    def _maybe_autostart(self):
        try:
            name = self.store.get_active_name()
            p = self.store.get_profile(name)
            if p.auto_start:
                self.append_log(f"Auto-start enabled for '{name}'. Starting…", "highlight")
                self.on_start()
        except Exception as e:
            self.append_log(f"Auto-start error: {e}", "error")

    # -------------------- Close --------------------

    def on_close(self):
        try:
            if self.engine.is_running():
                self.engine.stop()
                time.sleep(0.2)
        finally:
            self.destroy()
