"""
Poe2VisualTool Visual GUI & Companion Control Center
Giao diện điều khiển đồ họa hiện đại cho Poe2VisualTool (CustomTkinter).
Tính năng:
- Kết nối Shared Memory C++ Core Engine (Poe2VisualTool_v1).
- Thanh trượt điều khiển Zoom Cap (1.0x - 8.0x) hỗ trợ con lăn chuột.
- Checkbox Auto-Reveal Minimap (tự động mở sáng bản đồ POE2).
- Checkbox Xóa Sương Mù (volumetric fog removal).
- Checkbox Lọc màu vật phẩm (Auto-Hover Item Inspector HUD).
- Quản lý đường dẫn game POE2 tích hợp GamePathResolver 4 tầng + Nút [📂 Duyệt đường dẫn game...].
- Phím tắt khẩn cấp (Panic / Redetect / Restore Defaults).
Bối cảnh: 13/09/2026 (Rule 2)
"""

from __future__ import annotations

import mmap
import os
import struct
import subprocess
import sys
import time
from pathlib import Path
from typing import Optional

import customtkinter as ctk

from src.assistant.game_path_resolver import GamePathResolver
from src.assistant.item_hover_watcher import ItemHoverWatcher
from src.assistant.item_tooltip_overlay import ItemTooltipOverlay, apply_streamer_affinity
from src.commercial.hwid import get_machine_hwid
from src.commercial.license_manager import LicenseManager, LicenseInfo, LicenseTier
from src.commercial.license_dialog import LicenseDialog
from src.commercial.sound_manager import sound_manager

# Cấu hình hằng số Zoom & IPC (khớp với C++ Engine)
VISUAL_ZOOM_MIN = 1.0
VISUAL_ZOOM_MAX = 8.0
VISUAL_ZOOM_STEP = 0.10
VISUAL_ZFAR_CULLING_SCALE = 1.35
WHEEL_NOTCH = 120.0

VISUAL_TOOL_IPC_NAMES = (
    "Poe2VisualTool_v1",
    "Local\\Poe2VisualTool_v1",
    "Poe2VisualTool_IPC",
    "Local\\Poe2VisualTool_IPC",
    "AutoPOE2_VisualTool_v1",
    "Local\\AutoPOE2_VisualTool_v1",
    "AutoPOE2_VisualTool_IPC",
    "Local\\AutoPOE2_VisualTool_IPC",
)
VISUAL_TOOL_MAGIC = 0x56543031  # 'VT01'
IPC_STRUCT = struct.Struct("<IIffIIQQII")
assert IPC_STRUCT.size == 48

# Bit flags điều khiển
FLAG_ENABLE_ZOOM = 1 << 0
FLAG_DISABLE_FOG = 1 << 1
FLAG_WHEEL_DRIVE = 1 << 2
FLAG_PANIC = 1 << 3
FLAG_REDETECT = 1 << 4
FLAG_AUTO_REVEAL = 1 << 5
FLAG_MAP_CONTENT_RADAR = 1 << 6
FLAG_MOD_COLORIZER = 1 << 7
FLAG_PARTICLE_REDUCER = 1 << 8

# Bit flags trạng thái engine C++
STATUS_ATTACHED = 1 << 0
STATUS_CAMERA_OK = 1 << 1
STATUS_FOG_OK = 1 << 2
STATUS_RUNNING = 1 << 3
STATUS_POI_RADAR_OK = 1 << 4
STATUS_MOD_COLORIZER_OK = 1 << 5
STATUS_PARTICLE_REDUCER_OK = 1 << 6


def clamp_visual_zoom(multiplier: float) -> float:
    return max(VISUAL_ZOOM_MIN, min(VISUAL_ZOOM_MAX, float(multiplier)))


def visual_zfar_target(orig_zfar: float, multiplier: float) -> float:
    return float(orig_zfar) * (clamp_visual_zoom(multiplier) * VISUAL_ZFAR_CULLING_SCALE)


def apply_wheel_to_cap(current_cap: float, wheel_delta: int, step: float = VISUAL_ZOOM_STEP) -> float:
    notches = float(wheel_delta) / WHEEL_NOTCH
    return clamp_visual_zoom(float(current_cap) + notches * step)


def repo_root() -> Path:
    return Path(__file__).resolve().parents[2]


def find_visual_tool_exe() -> Optional[Path]:
    root = repo_root()
    candidates = (
        root / "bin" / "Release" / "Poe2VisualTool.exe",
        root / "bin" / "Poe2VisualTool.exe",
        root / "build" / "bin" / "Release" / "Poe2VisualTool.exe",
        root / "build" / "Release" / "Poe2VisualTool.exe",
        root / "Poe2VisualTool.exe",
        root / "bin" / "Release" / "AutoPOE2_VisualTool.exe",
        root / "bin" / "AutoPOE2_VisualTool.exe",
        root / "build" / "Release" / "AutoPOE2_VisualTool.exe",
    )
    for p in candidates:
        if p.is_file():
            return p
    return None


def is_visual_tool_engine_running() -> bool:
    try:
        import psutil
        for proc in psutil.process_iter(["name"]):
            name = (proc.info.get("name") or "").lower()
            if name in ("poe2visualtool.exe", "autopoe2_visualtool.exe"):
                return True
    except Exception:
        pass
    return False


class VisualToolIpc:
    """Quản lý kết nối Shared Memory IPC với C++ Core Engine."""

    def __init__(self) -> None:
        self._mm: Optional[mmap.mmap] = None
        self._active_tag: Optional[str] = None

    def open(self) -> bool:
        if self._mm is not None:
            return True

        for tag in VISUAL_TOOL_IPC_NAMES:
            try:
                mm = mmap.mmap(-1, IPC_STRUCT.size, tagname=tag)
                raw = mm[: IPC_STRUCT.size]
                magic = struct.unpack_from("<I", raw, 0)[0]
                self._mm = mm
                self._active_tag = tag
                if magic == 0:
                    self.write_defaults()
                return True
            except OSError:
                continue
            except Exception:
                continue
        return False

    def close(self) -> None:
        if self._mm is not None:
            try:
                self._mm.close()
            except Exception:
                pass
            self._mm = None
            self._active_tag = None

    def is_connected(self) -> bool:
        return self._mm is not None

    def write_defaults(self, cap: float = VISUAL_ZOOM_MAX, flags: int = 0) -> None:
        if self._mm is None:
            return
        try:
            payload = IPC_STRUCT.pack(
                VISUAL_TOOL_MAGIC, 0, clamp_visual_zoom(cap), 1.0,
                flags, 0, 0, 0, 0, 0,
            )
            self._mm.seek(0)
            self._mm.write(payload)
        except Exception:
            pass

    def read(self) -> Optional[dict]:
        if self._mm is None:
            return None
        try:
            self._mm.seek(0)
            raw = self._mm.read(IPC_STRUCT.size)
            if len(raw) != IPC_STRUCT.size:
                return None
            magic, seq, cap, cur, flags, status, cam, fog, pid, err = IPC_STRUCT.unpack(raw)
            return {
                "magic": magic,
                "seqlock": seq,
                "zoom_cap": cap,
                "current_zoom": cur,
                "flags": flags,
                "status": status,
                "camera_addr": cam,
                "fog_addr": fog,
                "pid": pid,
                "last_error": err,
                "is_attached": bool(status & STATUS_ATTACHED),
                "is_camera_ok": bool(status & STATUS_CAMERA_OK),
                "is_fog_ok": bool(status & STATUS_FOG_OK),
                "is_running": bool(status & STATUS_RUNNING),
                "is_auto_reveal": bool(flags & FLAG_AUTO_REVEAL),
                "is_poi_radar": bool(flags & FLAG_MAP_CONTENT_RADAR),
            }
        except Exception:
            return None

    def write_controls(self, cap: float, flags: int) -> None:
        """Atomic Partial Write: Chỉ cập nhật byte offset 8 (zoom_cap) và 16 (flags)."""
        if self._mm is None:
            return
        try:
            self._mm[8:12] = struct.pack("<f", clamp_visual_zoom(cap))
            self._mm[16:20] = struct.pack("<I", int(flags))
        except Exception:
            pass


def launch_visual_tool_engine(max_zoom: float = VISUAL_ZOOM_MAX, no_fog: bool = True) -> Optional[subprocess.Popen]:
    exe = find_visual_tool_exe()
    if exe is None:
        return None
    if is_visual_tool_engine_running():
        return None
    cmd = [str(exe), "--max-zoom", f"{clamp_visual_zoom(max_zoom):.1f}"]
    if no_fog:
        cmd.append("--no-fog")
    else:
        cmd.append("--fog")
    try:
        return subprocess.Popen(
            cmd,
            cwd=str(exe.parent),
            creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0),
        )
    except Exception:
        return None


class VisualGuiApp(ctk.CTk):
    """Cửa sổ điều khiển giao diện chính của Poe2VisualTool."""

    def __init__(self, start_engine: bool = True):
        super().__init__()
        self.title("Poe2VisualTool — Companion & Visual Engine")
        self.geometry("520x650")
        self.minsize(480, 600)
        ctk.set_appearance_mode("Dark")
        self.configure(fg_color="#0f172a")

        self.ipc = VisualToolIpc()
        self.path_resolver = GamePathResolver()
        self.license_manager = LicenseManager()
        self._last_attached = False
        self._engine: Optional[subprocess.Popen] = None
        self.overlay: Optional[ItemTooltipOverlay] = None
        self.watcher: Optional[ItemHoverWatcher] = None

        self._build_ui()
        self._init_inspector()
        self._update_license_ui()

        # Mở IPC
        self.ipc.open()
        default_flags = FLAG_ENABLE_ZOOM | FLAG_DISABLE_FOG | FLAG_WHEEL_DRIVE | FLAG_AUTO_REVEAL
        self.ipc.write_controls(VISUAL_ZOOM_MAX, default_flags)

        if start_engine:
            self._engine = launch_visual_tool_engine(VISUAL_ZOOM_MAX, True)

        self.protocol("WM_DELETE_WINDOW", self._on_close)
        self.after(150, self._poll_status)

    def _build_ui(self):
        # 1. Header Frame
        hdr = ctk.CTkFrame(self, fg_color="#1e293b", corner_radius=0)
        hdr.pack(fill="x")

        hdr_top = ctk.CTkFrame(hdr, fg_color="transparent")
        hdr_top.pack(fill="x", padx=16, pady=(12, 2))

        ctk.CTkLabel(
            hdr_top,
            text="⚡ Poe2VisualTool (Commercial 2026)",
            font=ctk.CTkFont(family="Segoe UI", size=18, weight="bold"),
            text_color="#f59e0b",
        ).pack(side="left")

        self.btn_license = ctk.CTkButton(
            hdr_top,
            text="🔑 KÍCH HOẠT",
            font=ctk.CTkFont(size=11, weight="bold"),
            width=130,
            height=26,
            fg_color="#334155",
            hover_color="#475569",
            command=self._open_license_dialog,
        )
        self.btn_license.pack(side="right")

        ctk.CTkLabel(
            hdr,
            text="Zoom Unlock 8x · Volumetric Fog Removal · Auto-Reveal Minimap · Item HUD",
            font=ctk.CTkFont(family="Segoe UI", size=11),
            text_color="#94a3b8",
        ).pack(anchor="w", padx=16, pady=(0, 12))

        # Main Scrollable / Content Frame
        content = ctk.CTkFrame(self, fg_color="transparent")
        content.pack(fill="both", expand=True, padx=14, pady=10)

        # 2. Game Path Card
        path_card = ctk.CTkFrame(content, fg_color="#1e293b", border_color="#334155", border_width=1, corner_radius=8)
        path_card.pack(fill="x", pady=(0, 10))

        ctk.CTkLabel(
            path_card,
            text="🎮 ĐƯỜNG DẪN PATH OF EXILE 2",
            font=ctk.CTkFont(size=12, weight="bold"),
            text_color="#38bdf8",
        ).pack(anchor="w", padx=14, pady=(10, 4))

        path_row = ctk.CTkFrame(path_card, fg_color="transparent")
        path_row.pack(fill="x", padx=14, pady=(0, 10))

        initial_path = self.path_resolver.resolve(allow_prompt=False) or "Chưa phát hiện (Nhấn nút duyệt bên cạnh)"
        self.entry_path = ctk.CTkEntry(
            path_row,
            placeholder_text="Đường dẫn PathOfExile.exe...",
            font=ctk.CTkFont(size=11),
            height=30,
        )
        self.entry_path.pack(side="left", fill="x", expand=True, padx=(0, 8))
        self.entry_path.insert(0, initial_path)

        self.btn_browse = ctk.CTkButton(
            path_row,
            text="📂 Duyệt đường dẫn game...",
            width=170,
            height=30,
            fg_color="#0284c7",
            hover_color="#0369a1",
            command=self._on_browse_game_path,
        )
        self.btn_browse.pack(side="right")

        # 3. Controls Card
        ctrl_card = ctk.CTkFrame(content, fg_color="#1e293b", border_color="#334155", border_width=1, corner_radius=8)
        ctrl_card.pack(fill="x", pady=(0, 10))

        ctk.CTkLabel(
            ctrl_card,
            text="🎛️ ĐIỀU KHIỂN TẦNG VISUAL & QOL",
            font=ctk.CTkFont(size=12, weight="bold"),
            text_color="#38bdf8",
        ).pack(anchor="w", padx=14, pady=(10, 6))

        # Checkbox Zoom
        self.chk_zoom = ctk.CTkCheckBox(
            ctrl_card,
            text="Mở khóa góc nhìn Zoom (con lăn chuột trong game)",
            font=ctk.CTkFont(size=13, weight="bold"),
            text_color="#e2e8f0",
            fg_color="#0284c7",
            command=self._push_controls,
        )
        self.chk_zoom.select()
        self.chk_zoom.pack(anchor="w", padx=14, pady=(2, 4))

        # Slider Zoom Cap
        self.lbl_cap = ctk.CTkLabel(
            ctrl_card,
            text="Trần Zoom tối đa: 8.0x (Lăn chuột trên thanh để điều chỉnh)",
            font=ctk.CTkFont(size=11),
            text_color="#94a3b8",
        )
        self.lbl_cap.pack(anchor="w", padx=18, pady=(2, 0))

        self.sld_cap = ctk.CTkSlider(
            ctrl_card,
            from_=VISUAL_ZOOM_MIN,
            to=VISUAL_ZOOM_MAX,
            number_of_steps=70,
            command=self._on_cap_slider,
        )
        self.sld_cap.set(VISUAL_ZOOM_MAX)
        self.sld_cap.pack(fill="x", padx=18, pady=(4, 8))
        self.sld_cap.bind("<MouseWheel>", self._on_cap_wheel)

        # Checkbox Xóa sương mù
        self.chk_fog = ctk.CTkCheckBox(
            ctrl_card,
            text="Xóa Sương Mù thể tích (Volumetric Fog Removal)",
            font=ctk.CTkFont(size=13, weight="bold"),
            text_color="#e2e8f0",
            fg_color="#0284c7",
            command=self._push_controls,
        )
        self.chk_fog.select()
        self.chk_fog.pack(anchor="w", padx=14, pady=(2, 4))

        # Checkbox Auto-Reveal Minimap
        self.chk_auto_reveal = ctk.CTkCheckBox(
            ctrl_card,
            text="Tự động mở sáng Minimap khi vào map (Auto-Reveal)",
            font=ctk.CTkFont(size=13, weight="bold"),
            text_color="#e2e8f0",
            fg_color="#0284c7",
            command=self._push_controls,
        )
        self.chk_auto_reveal.select()
        self.chk_auto_reveal.pack(anchor="w", padx=14, pady=(2, 4))

        # Checkbox Lọc màu vật phẩm
        self.chk_inspector = ctk.CTkCheckBox(
            ctrl_card,
            text="Lọc màu vật phẩm & Waystone (Item Hover Inspector HUD)",
            font=ctk.CTkFont(size=13, weight="bold"),
            text_color="#e2e8f0",
            fg_color="#0284c7",
            command=self._on_inspector_toggle,
        )
        self.chk_inspector.select()
        self.chk_inspector.pack(anchor="w", padx=14, pady=(2, 4))

        # Checkbox Chế độ Streamer (OBS Bypass)
        self.chk_streamer = ctk.CTkCheckBox(
            ctrl_card,
            text="Chế độ Streamer (Ẩn Tooltip khỏi OBS Studio & Discord)",
            font=ctk.CTkFont(size=13, weight="bold"),
            text_color="#e2e8f0",
            fg_color="#0284c7",
            command=self._on_streamer_toggle,
        )
        self.chk_streamer.select()
        self.chk_streamer.pack(anchor="w", padx=14, pady=(2, 4))

        # Checkbox POI Minimap Radar
        self.chk_radar = ctk.CTkCheckBox(
            ctrl_card,
            text="POI Minimap Radar (Định vị Boss, Strongbox, Shrine)",
            font=ctk.CTkFont(size=13, weight="bold"),
            text_color="#e2e8f0",
            fg_color="#0284c7",
            command=self._push_controls,
        )
        self.chk_radar.select()
        self.chk_radar.pack(anchor="w", padx=14, pady=(2, 4))

        # Checkbox FPS Booster (Particle Reducer)
        self.chk_booster = ctk.CTkCheckBox(
            ctrl_card,
            text="FPS Booster (Giảm hạt thời tiết, tắt rung màn hình, bloom)",
            font=ctk.CTkFont(size=13, weight="bold"),
            text_color="#e2e8f0",
            fg_color="#0284c7",
            command=self._push_controls,
        )
        self.chk_booster.pack(anchor="w", padx=14, pady=(2, 4))

        # Checkbox Tô màu mod trong RAM
        self.chk_mod_colors = ctk.CTkCheckBox(
            ctrl_card,
            text="Tô màu phân loại Mod trang bị trong RAM (Đỏ/Lam/Lục/Vàng)",
            font=ctk.CTkFont(size=13, weight="bold"),
            text_color="#e2e8f0",
            fg_color="#0284c7",
            command=self._push_controls,
        )
        self.chk_mod_colors.pack(anchor="w", padx=14, pady=(2, 10))

        # 4. Status Card
        status_card = ctk.CTkFrame(content, fg_color="#182230", border_color="#0284c7", border_width=1, corner_radius=8)
        status_card.pack(fill="x", pady=(0, 10))

        status_header = ctk.CTkFrame(status_card, fg_color="transparent")
        status_header.pack(fill="x", padx=12, pady=(8, 2))

        ctk.CTkLabel(
            status_header,
            text="TRẠNG THÁI C++ CORE ENGINE (IPC)",
            font=ctk.CTkFont(size=11, weight="bold"),
            text_color="#38bdf8",
        ).pack(side="left")

        self.lbl_ipc_badge = ctk.CTkLabel(
            status_header,
            text="ĐANG QUÉT...",
            font=ctk.CTkFont(size=10, weight="bold"),
            text_color="#f59e0b",
        )
        self.lbl_ipc_badge.pack(side="right")

        self.lbl_status = ctk.CTkLabel(
            status_card,
            text="Đang kết nối Shared Memory Poe2VisualTool_v1...",
            font=ctk.CTkFont(size=11),
            text_color="#cbd5e1",
            justify="left",
            wraplength=460,
        )
        self.lbl_status.pack(anchor="w", padx=12, pady=(2, 8))

        # 5. Buttons Row
        btns_row = ctk.CTkFrame(content, fg_color="transparent")
        btns_row.pack(fill="x", pady=(2, 0))

        self.btn_launch = ctk.CTkButton(
            btns_row,
            text="🚀 Khởi động Engine",
            width=140,
            height=32,
            fg_color="#059669",
            hover_color="#047857",
            command=self._on_launch_engine,
        )
        self.btn_launch.pack(side="left", padx=(0, 8))

        self.btn_redetect = ctk.CTkButton(
            btns_row,
            text="🔄 Dò lại camera",
            width=130,
            height=32,
            fg_color="#0284c7",
            hover_color="#0369a1",
            command=self._on_redetect,
        )
        self.btn_redetect.pack(side="left", padx=(0, 8))

        self.btn_panic = ctk.CTkButton(
            btns_row,
            text="🛑 Hoàn nguyên (Panic)",
            width=140,
            height=32,
            fg_color="#dc2626",
            hover_color="#b91c1c",
            command=self._on_panic,
        )
        self.btn_panic.pack(side="left")

    def _init_inspector(self):
        """Khởi tạo HUD Overlay và bộ giám sát con trỏ chuột ItemHoverWatcher."""
        try:
            self.overlay = ItemTooltipOverlay(root=self)
            self.watcher = ItemHoverWatcher(
                on_item_inspected=lambda rep, x, y: self.overlay.show(rep, x, y) if self.overlay else None,
                on_cursor_moved=lambda: self.overlay.hide() if self.overlay else None,
                dwell_time_ms=180.0,
                enable_focus_interlock=True,
            )
            if self.chk_inspector.get():
                self.watcher.start()
        except Exception:
            self.overlay = None
            self.watcher = None

    def _on_browse_game_path(self):
        """Mở hộp thoại chọn tệp game và cập nhật giao diện + config.toml tức thì."""
        chosen = self.path_resolver.prompt_user_for_exe(parent=self)
        if chosen:
            self.entry_path.delete(0, "end")
            self.entry_path.insert(0, chosen)
            self.lbl_status.configure(text=f"Đã lưu đường dẫn game: {chosen}")

    def _flags_from_ui(self) -> int:
        flags = 0
        if self.chk_zoom.get():
            flags |= FLAG_ENABLE_ZOOM
            flags |= FLAG_WHEEL_DRIVE
        if self.chk_fog.get():
            flags |= FLAG_DISABLE_FOG
        if self.chk_auto_reveal.get():
            flags |= FLAG_AUTO_REVEAL
        if hasattr(self, "chk_radar") and self.chk_radar.get():
            flags |= FLAG_MAP_CONTENT_RADAR
        if hasattr(self, "chk_booster") and self.chk_booster.get():
            flags |= FLAG_PARTICLE_REDUCER
        if hasattr(self, "chk_mod_colors") and self.chk_mod_colors.get():
            flags |= FLAG_MOD_COLORIZER
        return flags

    def _push_controls(self):
        cap = float(self.sld_cap.get())
        flags = self._flags_from_ui()
        self.ipc.write_controls(cap, flags)

    def _on_cap_slider(self, val):
        cap = clamp_visual_zoom(float(val))
        zfar = visual_zfar_target(150.0, cap)
        self.lbl_cap.configure(text=f"Trần Zoom tối đa: {cap:.1f}x (zFar bù culling ~{zfar:.0f}) — Lăn chuột để chỉnh")
        self._push_controls()

    def _on_cap_wheel(self, event):
        cap = apply_wheel_to_cap(float(self.sld_cap.get()), int(event.delta))
        self.sld_cap.set(cap)
        self._on_cap_slider(cap)
        return "break"

    def _on_inspector_toggle(self):
        if not self.watcher:
            return
        if self.chk_inspector.get():
            self.watcher.start()
        else:
            self.watcher.stop()
            if self.overlay:
                self.overlay.hide()

    def _on_launch_engine(self):
        if is_visual_tool_engine_running():
            self.lbl_status.configure(text="C++ Core Engine đã đang chạy!")
            return
        self._engine = launch_visual_tool_engine(float(self.sld_cap.get()), bool(self.chk_fog.get()))
        if self._engine is not None:
            self.lbl_status.configure(text="Đang khởi động C++ Core Engine...")
        else:
            exe = find_visual_tool_exe()
            if exe is None:
                self.lbl_status.configure(text="Chưa tìm thấy tệp Poe2VisualTool.exe.")
            else:
                self.lbl_status.configure(text="Không thể khởi động Engine.")

    def _on_redetect(self):
        flags = self._flags_from_ui() | FLAG_REDETECT
        self.ipc.write_controls(float(self.sld_cap.get()), flags)
        self.lbl_status.configure(text="Đã gửi lệnh dò lại địa chỉ Camera/Fog trong RAM...")

    def _on_streamer_toggle(self):
        enabled = bool(self.chk_streamer.get())
        if self.overlay and hasattr(self.overlay, "target_hwnd"):
            apply_streamer_affinity(self.overlay.target_hwnd, enabled)

    def _open_license_dialog(self):
        LicenseDialog(self, license_manager=self.license_manager, on_success=lambda info: self._update_license_ui())

    def _update_license_ui(self):
        info = self.license_manager.load_license()
        if info.is_valid:
            if info.tier == LicenseTier.LIFETIME:
                self.btn_license.configure(text="🛡️ VĨNH VIỄN", fg_color="#059669", hover_color="#047857")
            elif info.tier == LicenseTier.SUBSCRIPTION:
                self.btn_license.configure(text=f"⏳ {info.days_left} NGÀY", fg_color="#0284c7", hover_color="#0369a1")
            elif info.tier == LicenseTier.TRIAL:
                self.btn_license.configure(text=f"🎁 TRIAL {info.days_left}d", fg_color="#d97706", hover_color="#b45309")
        else:
            self.btn_license.configure(text="🔑 KÍCH HOẠT", fg_color="#dc2626", hover_color="#b91c1c")

    def _on_panic(self):
        sound_manager.play_panic_restore()
        flags = self._flags_from_ui() | FLAG_PANIC
        self.ipc.write_controls(float(self.sld_cap.get()), flags)
        self.chk_zoom.deselect()
        self.chk_fog.deselect()
        if hasattr(self, "chk_booster"):
            self.chk_booster.deselect()
        if hasattr(self, "chk_mod_colors"):
            self.chk_mod_colors.deselect()
        self.lbl_status.configure(text="Đã kích hoạt chế độ Hoàn nguyên (Panic)!")

    def _poll_status(self):
        if not self.winfo_exists():
            return

        if not self.ipc.is_connected():
            self.ipc.open()

        st = self.ipc.read()
        engine_running = is_visual_tool_engine_running()

        if st is not None:
            attached = bool(st["status"] & STATUS_ATTACHED)
            cam = bool(st["status"] & STATUS_CAMERA_OK)
            fog = bool(st["status"] & STATUS_FOG_OK)

            if attached:
                self.lbl_ipc_badge.configure(text="● CONNECTED", text_color="#10b981")
                if not self._last_attached:
                    sound_manager.play_attach_success()
            elif engine_running:
                self.lbl_ipc_badge.configure(text="● ENGINE STANDBY", text_color="#38bdf8")
            else:
                self.lbl_ipc_badge.configure(text="○ WAITING ENGINE", text_color="#f59e0b")
            self._last_attached = attached

            bits = []
            bits.append(f"Gắn PID {st['pid']}" if attached else "Chờ tiến trình PathOfExile.exe")
            bits.append("Camera OK" if cam else "Chưa thấy Camera")
            bits.append("Fog OK" if fog else "Chưa thấy Fog")
            bits.append(f"Zoom {st['current_zoom']:.1f}x")
            if bool(st.get("flags", 0) & FLAG_AUTO_REVEAL):
                bits.append("Minimap Auto-Reveal ON")
            if bool(st.get("flags", 0) & FLAG_MAP_CONTENT_RADAR):
                bits.append("Radar ON")
            if bool(st.get("flags", 0) & FLAG_PARTICLE_REDUCER):
                bits.append("FPS Booster ON")
            if bool(st.get("flags", 0) & FLAG_MOD_COLORIZER):
                bits.append("Mod Colorizer ON")
            if self.watcher and self.watcher.is_running:
                bits.append("Item HUD ON")

            self.lbl_status.configure(text=" · ".join(bits))
        else:
            self.lbl_ipc_badge.configure(text="○ DISCONNECTED", text_color="#ef4444")
            exe = find_visual_tool_exe()
            if exe is None:
                self.lbl_status.configure(text="Chưa biên dịch Poe2VisualTool.exe trong thư mục bin/ hoặc build/.")
            else:
                self.lbl_status.configure(text="IPC chưa mở — Hãy nhấn [🚀 Khởi động Engine] để kích hoạt.")

        self.after(200, self._poll_status)

    def _on_close(self):
        if self.watcher:
            try:
                self.watcher.stop()
            except Exception:
                pass
        if self.overlay:
            try:
                self.overlay.hide()
            except Exception:
                pass
        self.ipc.write_controls(float(self.sld_cap.get()), FLAG_PANIC)
        time.sleep(0.08)
        self.ipc.close()
        self.destroy()


def main():
    if hasattr(sys.stdout, "reconfigure"):
        sys.stdout.reconfigure(encoding="utf-8")
    app = VisualGuiApp(start_engine=True)
    app.mainloop()


if __name__ == "__main__":
    main()
