#!/bin/bash
# ==============================================================================
# Sen Việt (VieLotusIM) — Linux Desktop Settings Utility
# Supports both Fcitx5 (fcitx5-configtool) and IBus (GNOME Input Sources)
# ==============================================================================

UID_CUR="$(id -u 2>/dev/null || echo 1000)"
CONFIG_ROOT="${XDG_CONFIG_HOME:-$HOME/.config}"
DATA_ROOT="${XDG_DATA_HOME:-$HOME/.local/share}"
CONFIG_DIR="${CONFIG_ROOT}/vielotus"
mkdir -p "${CONFIG_DIR}" 2>/dev/null || true
if [ ! -w "${CONFIG_DIR}" ]; then
    CONFIG_DIR="/tmp/vielotus-cfg-${UID_CUR}"
    mkdir -p "${CONFIG_DIR}" 2>/dev/null || true
fi
CONFIG_FILE="${CONFIG_DIR}/config.env"
LOG_FILE="${CONFIG_DIR}/settings.log"

INPUT_METHOD="telex"
GRAMMAR_PROFILE="sen_flex"
SMART_BILINGUAL="true"
MODERN_ORTHOGRAPHY="true"
QUICK_TELEX="false"
RELAXED_CODA="false"
MACRO_ENABLED="true"
DEVELOPER_MODE="false"
PREEDIT_UNDERLINE="false"

load_config() {
    if [ ! -f "${CONFIG_FILE}" ]; then
        return 0
    fi
    while IFS='=' read -r raw_key raw_val || [ -n "${raw_key}" ]; do
        key=$(printf '%s' "${raw_key}" | tr -d '[:space:]')
        case "${key}" in
            ''|\#*) continue ;;
        esac
        val=$(printf '%s' "${raw_val}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/^"//' -e 's/"$//' -e "s/^'//" -e "s/'$//")
        case "${key}" in
            INPUT_METHOD)
                case "${val}" in
                    vni|VNI) INPUT_METHOD="vni" ;;
                    *) INPUT_METHOD="telex" ;;
                esac
                ;;
            GRAMMAR_PROFILE)
                case "${val}" in
                    classic|Classic|CLASSIC) GRAMMAR_PROFILE="classic" ;;
                    *) GRAMMAR_PROFILE="sen_flex" ;;
                esac
                ;;
            SMART_BILINGUAL)
                case "${val}" in
                    false|False|FALSE|0) SMART_BILINGUAL="false" ;;
                    *) SMART_BILINGUAL="true" ;;
                esac
                ;;
            MODERN_ORTHOGRAPHY)
                case "${val}" in
                    false|False|FALSE|0) MODERN_ORTHOGRAPHY="false" ;;
                    *) MODERN_ORTHOGRAPHY="true" ;;
                esac
                ;;
            QUICK_TELEX)
                case "${val}" in
                    true|True|TRUE|1) QUICK_TELEX="true" ;;
                    *) QUICK_TELEX="false" ;;
                esac
                ;;
            RELAXED_CODA)
                case "${val}" in
                    true|True|TRUE|1) RELAXED_CODA="true" ;;
                    *) RELAXED_CODA="false" ;;
                esac
                ;;
            MACRO_ENABLED)
                case "${val}" in
                    false|False|FALSE|0) MACRO_ENABLED="false" ;;
                    *) MACRO_ENABLED="true" ;;
                esac
                ;;
            DEVELOPER_MODE)
                case "${val}" in
                    true|True|TRUE|1) DEVELOPER_MODE="true" ;;
                    *) DEVELOPER_MODE="false" ;;
                esac
                ;;
            PREEDIT_UNDERLINE)
                case "${val}" in
                    true|True|TRUE|1) PREEDIT_UNDERLINE="true" ;;
                    *) PREEDIT_UNDERLINE="false" ;;
                esac
                ;;
        esac
    done < "${CONFIG_FILE}"
}

load_config

configure_fcitx5_profile() {
    FCITX_IM="$1"
    ACTIVATE_PROFILE="${2:-0}"
    FCITX_PROFILE_DIR="${CONFIG_ROOT}/fcitx5"
    FCITX_PROFILE="${FCITX_PROFILE_DIR}/profile"
    mkdir -p "${FCITX_PROFILE_DIR}/conf"

    FCITX_GRAMMAR="SenFlex"
    if [ "${GRAMMAR_PROFILE}" = "classic" ]; then
        FCITX_GRAMMAR="Classic"
    fi
    FCITX_SB="True"
    [ "${SMART_BILINGUAL}" = "false" ] && FCITX_SB="False"
    FCITX_MOD="True"
    [ "${MODERN_ORTHOGRAPHY}" = "false" ] && FCITX_MOD="False"
    FCITX_QT="False"
    [ "${QUICK_TELEX}" = "true" ] && FCITX_QT="True"

    cat <<FCITX_CONF_EOF > "${FCITX_PROFILE_DIR}/conf/vielotus.conf"
# Chế độ đặt dấu (Grammar Profile)
GrammarProfile=${FCITX_GRAMMAR}
# Song ngữ thông minh Anh-Việt (Smart Bilingual)
SmartBilingual=${FCITX_SB}
# Chính tả hiện đại: oà, uý (thay vì òa, úy)
ModernOrthography=${FCITX_MOD}
# Gõ tắt phụ âm (Quick Telex: cc=ch, gg=gi, kk=kh...)
QuickTelex=${FCITX_QT}
FCITX_CONF_EOF

    if [ "${ACTIVATE_PROFILE}" = "1" ] && [ -f "${FCITX_PROFILE}" ] && command -v python3 >/dev/null 2>&1; then
        python3 - "${FCITX_PROFILE}" "${FCITX_IM}" <<'PYEOF' 2>/dev/null || true
import re, sys

profile_path, im_name = sys.argv[1], sys.argv[2]
with open(profile_path, "r", encoding="utf-8", errors="ignore") as f:
    text = f.read()

if re.search(r"^Name=vielotus-(telex|vni)$", text, flags=re.M):
    text = re.sub(r"^Name=vielotus-(telex|vni)$", f"Name={im_name}", text, count=1, flags=re.M)
    with open(profile_path, "w", encoding="utf-8") as f:
        f.write(text)
PYEOF
    fi
}

save_and_apply() {
    MODE="${1:-$INPUT_METHOD}"
    ACTIVATE_SOURCES="${2:-0}"
    case "${MODE}" in
        vni|VNI) INPUT_METHOD="vni" ;;
        *) INPUT_METHOD="telex" ;;
    esac

    cat <<ENV_EOF > "${CONFIG_FILE}"
INPUT_METHOD="${INPUT_METHOD}"
GRAMMAR_PROFILE="${GRAMMAR_PROFILE}"
SMART_BILINGUAL="${SMART_BILINGUAL}"
MODERN_ORTHOGRAPHY="${MODERN_ORTHOGRAPHY}"
QUICK_TELEX="${QUICK_TELEX}"
RELAXED_CODA="${RELAXED_CODA}"
MACRO_ENABLED="${MACRO_ENABLED}"
DEVELOPER_MODE="${DEVELOPER_MODE}"
PREEDIT_UNDERLINE="${PREEDIT_UNDERLINE}"
ENV_EOF

    ENGINE_ID="vielotus"
    FCITX_IM_ID="vielotus-telex"
    if [ "${INPUT_METHOD}" = "vni" ]; then
        ENGINE_ID="vielotus-vni"
        FCITX_IM_ID="vielotus-vni"
    fi

    # 1. Update Fcitx5 addon config file
    configure_fcitx5_profile "${FCITX_IM_ID}" "${ACTIVATE_SOURCES}" || true

    # Reload/switch Fcitx5 if running
    if command -v fcitx5 >/dev/null 2>&1; then
        if pgrep -x fcitx5 >/dev/null 2>&1 || [ "${XMODIFIERS:-}" = "@im=fcitx" ] || [ "${GTK_IM_MODULE:-}" = "fcitx" ]; then
            if command -v fcitx5-remote >/dev/null 2>&1; then
                fcitx5-remote -r >/dev/null 2>&1 || true
                if [ "${ACTIVATE_SOURCES}" = "1" ]; then
                    fcitx5-remote -s "${FCITX_IM_ID}" >/dev/null 2>&1 || true
                fi
            fi
        fi
    fi

    # 2. Switch active IBus engine if IBus daemon is reachable and user explicitly changed mode
    if [ "${ACTIVATE_SOURCES}" = "1" ] && command -v ibus >/dev/null 2>&1; then
        if pgrep -x ibus-daemon >/dev/null 2>&1; then
            (ibus engine "${ENGINE_ID}" >/dev/null 2>&1 || true) &
        fi
    fi

    # 3. If user explicitly switched Telex/VNI or activated, update existing vielotus entry in GNOME Input Sources without touching other input sources
    if [ "${ACTIVATE_SOURCES}" = "1" ] && command -v gsettings >/dev/null 2>&1 && command -v python3 >/dev/null 2>&1; then
        python3 - "${ENGINE_ID}" <<'PYEOF' 2>/dev/null || true
import ast, subprocess, sys
engine_id = sys.argv[1]

def get_sources_list(key):
    try:
        raw = subprocess.check_output(
            ["gsettings", "get", "org.gnome.desktop.input-sources", key],
            stderr=subprocess.DEVNULL
        ).decode().strip()
        if raw.startswith("@a(ss) "):
            raw = raw[len("@a(ss) "):]
        return list(ast.literal_eval(raw)) if raw else []
    except Exception:
        return []

sources = get_sources_list("sources")
if any(s[0] == "ibus" and s[1] in ("vielotus", "vielotus-vni") for s in sources):
    sources = [("ibus", engine_id) if (s[0] == "ibus" and s[1] in ("vielotus", "vielotus-vni")) else s for s in sources]
    formatted_sources = "[" + ", ".join(f"('{k}', '{v}')" for k, v in sources) + "]"
    subprocess.call(
        ["gsettings", "set", "org.gnome.desktop.input-sources", "sources", formatted_sources],
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
    )
PYEOF
    fi
}

run_gtk_settings() {
    SMOKE_MODE="${1:-0}"
    python3 - "${CONFIG_FILE}" "${SMOKE_MODE}" <<'GTK_PYEOF'
import os, subprocess, sys, webbrowser

try:
    import gi
    gi.require_version("Gtk", "3.0")
    from gi.repository import Gtk, Gdk, GLib
except Exception:
    sys.exit(2)

ok, _ = Gtk.init_check(sys.argv[:1])
if not ok:
    sys.exit(2)

config_path = sys.argv[1]
smoke_mode = len(sys.argv) > 2 and sys.argv[2] == "1"

cfg = {
    "INPUT_METHOD": "telex",
    "GRAMMAR_PROFILE": "sen_flex",
    "SMART_BILINGUAL": "true",
    "MODERN_ORTHOGRAPHY": "true",
    "QUICK_TELEX": "false",
    "RELAXED_CODA": "false",
    "MACRO_ENABLED": "true",
    "DEVELOPER_MODE": "false",
    "PREEDIT_UNDERLINE": "false",
}
if os.path.exists(config_path):
    with open(config_path, "r", encoding="utf-8", errors="ignore") as f:
        for line in f:
            if "=" in line and not line.lstrip().startswith("#"):
                k, v = line.strip().split("=", 1)
                cfg[k.strip()] = v.strip().strip('"').strip("'")

# Always-On Smart Engine parity with macOS
cfg["SMART_BILINGUAL"] = "true"
cfg["MODERN_ORTHOGRAPHY"] = "true"

css = b"""
* { font-family: "Noto Sans", "DejaVu Sans", "Liberation Sans", "Ubuntu", sans-serif; }
.bento-win { background-color: #f5f5f7; }
.bento-header { background-color: #ffffff; border-bottom: 1px solid #e5e5ea; padding: 10px 16px; }
.bento-footer { background-color: #ffffff; border-top: 1px solid #e5e5ea; padding: 8px 16px; }
.bento-card { background-color: #ffffff; border: 1px solid #e2e2e8; border-radius: 10px; padding: 10px 12px; }
.bento-card-active { background-color: #ecf5ff; border: 2px solid #007aff; border-radius: 10px; padding: 10px 12px; }
.bento-strip { background-color: #edeefd; border: 1px solid #c6caf8; border-radius: 9px; padding: 8px 12px; }
"""
style_provider = Gtk.CssProvider()
try:
    style_provider.load_from_data(css)
    screen = Gdk.Screen.get_default()
    if screen is not None:
        Gtk.StyleContext.add_provider_for_screen(
            screen, style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )
except Exception:
    pass

win = Gtk.Window(title="Sen Việt (VieLotusIM) — Cài đặt")
try:
    GLib.set_prgname("vielotus")
    GLib.set_application_name("Sen Việt")
except Exception:
    pass
win.set_default_size(520, 510)
win.set_resizable(False)
win.set_position(Gtk.WindowPosition.CENTER)
win.get_style_context().add_class("bento-win")
try:
    win.set_icon_name("vielotus")
except Exception:
    pass

root_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
win.add(root_vbox)

# 1. Top Header Bar (Matches macOS SettingsView.swift: Brand + 2-Tab Switcher)
header_bar = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12)
header_bar.get_style_context().add_class("bento-header")

brand_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2)
title_lbl = Gtk.Label()
title_lbl.set_markup(
    "<span size='large' weight='bold' foreground='#1c1c1e'>🌸 Sen Việt</span> "
    "<span size='small' weight='bold' foreground='#007aff'>v2.0.1</span>"
)
title_lbl.set_xalign(0)
sub_lbl = Gtk.Label()
sub_lbl.set_markup("<span size='small' foreground='#6e6e73'>IBus &amp; Fcitx5 Native • Không quyền Trợ năng</span>")
sub_lbl.set_xalign(0)
brand_vbox.pack_start(title_lbl, False, False, 0)
brand_vbox.pack_start(sub_lbl, False, False, 0)
header_bar.pack_start(brand_vbox, True, True, 0)

stack = Gtk.Stack()
stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
stack.set_transition_duration(120)

stack_switcher = Gtk.StackSwitcher()
stack_switcher.set_stack(stack)
header_bar.pack_end(stack_switcher, False, False, 0)
root_vbox.pack_start(header_bar, False, False, 0)

def save_current_config(*_):
    os.makedirs(os.path.dirname(config_path), exist_ok=True)
    with open(config_path, "w", encoding="utf-8") as f:
        for key in (
            "INPUT_METHOD",
            "GRAMMAR_PROFILE",
            "SMART_BILINGUAL",
            "MODERN_ORTHOGRAPHY",
            "QUICK_TELEX",
            "RELAXED_CODA",
            "MACRO_ENABLED",
            "DEVELOPER_MODE",
            "PREEDIT_UNDERLINE",
        ):
            f.write(f'{key}="{cfg[key]}"\n')
    settings_bin = "/usr/bin/vielotus-settings"
    if not os.path.exists(settings_bin):
        settings_bin = os.path.abspath(sys.argv[0])
    im_flag = "--vni" if cfg["INPUT_METHOD"] == "vni" else "--telex"
    if smoke_mode:
        subprocess.call([settings_bin, im_flag])
    else:
        subprocess.Popen(
            [settings_bin, im_flag],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
        )

# ==============================================================================
# TAB 1: CÀI ĐẶT (Matches macOS 2-Card Hero + 2x2 Bento Grid + Smart Strip)
# ==============================================================================
tab_settings = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
tab_settings.set_border_width(14)

# Section 1 Header
sec1_hdr = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
sec1_left = Gtk.Label()
sec1_left.set_markup("<span size='small' weight='bold' foreground='#6e6e73'>KIỂU GÕ TIẾNG VIỆT</span>")
sec1_left.set_xalign(0)
sec1_right = Gtk.Label()
sec1_right.set_markup("<span size='small' weight='bold' foreground='#007aff'>Bỏ dấu tự do mọi vị trí</span>")
sec1_right.set_xalign(1)
sec1_hdr.pack_start(sec1_left, True, True, 0)
sec1_hdr.pack_end(sec1_right, False, False, 0)
tab_settings.pack_start(sec1_hdr, False, False, 0)

# Hero Input Method Cards (Telex Tự Do vs VNI Chuẩn)
hero_grid = Gtk.Grid()
hero_grid.set_column_homogeneous(True)
hero_grid.set_column_spacing(10)

btn_telex = Gtk.Button()
btn_vni = Gtk.Button()

def refresh_hero_cards():
    is_vni = cfg["INPUT_METHOD"] == "vni"
    for btn, active in ((btn_telex, not is_vni), (btn_vni, is_vni)):
        ctx = btn.get_style_context()
        ctx.remove_class("bento-card")
        ctx.remove_class("bento-card-active")
        ctx.add_class("bento-card-active" if active else "bento-card")

def build_hero_card_content(title, code_pill, desc):
    box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4)
    l1 = Gtk.Label()
    l1.set_markup(f"<span weight='bold' foreground='#1c1c1e'>{title}</span>")
    l1.set_xalign(0)
    l2 = Gtk.Label()
    l2.set_markup(
        f"<tt><span size='small' weight='bold' foreground='#007aff'>[{code_pill}]</span></tt> "
        f"<span size='small' foreground='#6e6e73'>{desc}</span>"
    )
    l2.set_xalign(0)
    box.pack_start(l1, False, False, 0)
    box.pack_start(l2, False, False, 0)
    return box

btn_telex.add(build_hero_card_content("Telex Tự Do", "s f r x j w", "vieetj → việt • w → ư"))
btn_vni.add(build_hero_card_content("VNI Chuẩn", "1–5 • 6–9", "vie65t → việt • 9 → đ"))

def on_select_im(mode):
    if cfg["INPUT_METHOD"] != mode:
        cfg["INPUT_METHOD"] = mode
        refresh_hero_cards()
        save_current_config()

btn_telex.connect("clicked", lambda *_: on_select_im("telex"))
btn_vni.connect("clicked", lambda *_: on_select_im("vni"))
refresh_hero_cards()

hero_grid.attach(btn_telex, 0, 0, 1, 1)
hero_grid.attach(btn_vni, 1, 0, 1, 1)
tab_settings.pack_start(hero_grid, False, False, 0)

# Section 2 Header
sec2_lbl = Gtk.Label()
sec2_lbl.set_markup("<span size='small' weight='bold' foreground='#6e6e73'>TIỆN ÍCH &amp; KHÔNG GIAN LÀM VIỆC</span>")
sec2_lbl.set_xalign(0)
tab_settings.pack_start(sec2_lbl, False, False, 0)

# 2x2 Bento Feature Grid
bento_grid = Gtk.Grid()
bento_grid.set_column_homogeneous(True)
bento_grid.set_row_homogeneous(True)
bento_grid.set_column_spacing(10)
bento_grid.set_row_spacing(10)

# Tile 1: Bảng gõ tắt
tile1 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
tile1.get_style_context().add_class("bento-card")
t1_top = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
t1_lbl = Gtk.Label()
t1_lbl.set_markup("<span weight='bold' foreground='#1c1c1e'>Bảng gõ tắt</span>")
t1_lbl.set_xalign(0)
sw_macro = Gtk.Switch()
sw_macro.set_active(cfg["MACRO_ENABLED"] != "false")
t1_top.pack_start(t1_lbl, True, True, 0)
t1_top.pack_end(sw_macro, False, False, 0)

t1_bot = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
t1_sub = Gtk.Label()
def update_macro_sub():
    on = sw_macro.get_active()
    t1_sub.set_markup(
        f"<span size='small' foreground='#6e6e73'>{'Đang bật • 38 cụm từ' if on else 'Đang tắt gõ tắt'}</span>"
    )
update_macro_sub()
t1_sub.set_xalign(0)
btn_macro_mgr = Gtk.Button(label="Quản lý")
def on_open_macros(*_):
    macro_file = os.path.join(os.path.dirname(config_path), "macros.json")
    if not os.path.exists(macro_file):
        os.makedirs(os.path.dirname(macro_file), exist_ok=True)
        with open(macro_file, "w", encoding="utf-8") as mf:
            mf.write('{\n  "ks": "Khách sạn",\n  "vn": "Việt Nam",\n  "tphcm": "TP. Hồ Chí Minh",\n  "ko": "không"\n}\n')
    try:
        subprocess.Popen(["xdg-open", macro_file])
    except Exception:
        pass
btn_macro_mgr.connect("clicked", on_open_macros)
t1_bot.pack_start(t1_sub, True, True, 0)
t1_bot.pack_end(btn_macro_mgr, False, False, 0)
tile1.pack_start(t1_top, False, False, 0)
tile1.pack_start(t1_bot, False, False, 0)

def on_macro_toggled(sw, _pspec):
    cfg["MACRO_ENABLED"] = "true" if sw.get_active() else "false"
    update_macro_sub()
    save_current_config()
sw_macro.connect("notify::active", on_macro_toggled)

# Tile 2: Chế độ Code & Dev
tile2 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
tile2.get_style_context().add_class("bento-card")
t2_top = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
t2_lbl = Gtk.Label()
t2_lbl.set_markup("<span weight='bold' foreground='#1c1c1e'>Chế độ Code &amp; Dev</span>")
t2_lbl.set_xalign(0)
sw_dev = Gtk.Switch()
sw_dev.set_active(cfg["DEVELOPER_MODE"] == "true")
t2_top.pack_start(t2_lbl, True, True, 0)
t2_top.pack_end(sw_dev, False, False, 0)
t2_sub = Gtk.Label()
def update_dev_sub():
    on = sw_dev.get_active()
    t2_sub.set_markup(
        f"<span size='small' foreground='#6e6e73'>{'Tự ngắt dấu trong `code`' if on else 'Gõ tiếng Việt bình thường'}</span>"
    )
update_dev_sub()
t2_sub.set_xalign(0)
tile2.pack_start(t2_top, False, False, 0)
tile2.pack_start(t2_sub, False, False, 0)

def on_dev_toggled(sw, _pspec):
    cfg["DEVELOPER_MODE"] = "true" if sw.get_active() else "false"
    update_dev_sub()
    save_current_config()
sw_dev.connect("notify::active", on_dev_toggled)

# Tile 3: Tốc gõ phụ âm (2 chips: Đầu cc/gg/qq & Cuối -g/-h/-k)
tile3 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
tile3.get_style_context().add_class("bento-card")
t3_lbl = Gtk.Label()
t3_lbl.set_markup("<span weight='bold' foreground='#1c1c1e'>⚡ Tốc gõ phụ âm</span>")
t3_lbl.set_xalign(0)
t3_chips = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
chk_qt = Gtk.ToggleButton(label="Đầu (cc/gg/qq)")
chk_qt.set_active(cfg["QUICK_TELEX"] == "true")
chk_rc = Gtk.ToggleButton(label="Cuối (-g/-h/-k)")
chk_rc.set_active(cfg["RELAXED_CODA"] == "true")
t3_chips.pack_start(chk_qt, True, True, 0)
t3_chips.pack_start(chk_rc, True, True, 0)
tile3.pack_start(t3_lbl, False, False, 0)
tile3.pack_start(t3_chips, False, False, 0)

def on_qt_toggled(btn):
    cfg["QUICK_TELEX"] = "true" if btn.get_active() else "false"
    save_current_config()
def on_rc_toggled(btn):
    cfg["RELAXED_CODA"] = "true" if btn.get_active() else "false"
    save_current_config()
chk_qt.connect("toggled", on_qt_toggled)
chk_rc.connect("toggled", on_rc_toggled)

# Tile 4: Đa ứng dụng (Riêng từng cửa sổ) & Hiển thị gạch chân
tile4 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
tile4.get_style_context().add_class("bento-card")
t4_top = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
t4_lbl = Gtk.Label()
t4_lbl.set_markup("<span weight='bold' foreground='#1c1c1e'>Đa ứng dụng &amp; Hiển thị</span>")
t4_lbl.set_xalign(0)
btn_fcitx = Gtk.Button(label="Phím tắt ↗")
def on_fcitx_clicked(_btn):
    for cmd in (["gnome-control-center", "keyboard"], ["fcitx5-configtool"], ["fcitx5-config-qt"]):
        try:
            subprocess.Popen(cmd)
            return
        except Exception:
            pass
btn_fcitx.connect("clicked", on_fcitx_clicked)
t4_top.pack_start(t4_lbl, True, True, 0)
t4_top.pack_end(btn_fcitx, False, False, 0)

def get_gnome_per_window():
    try:
        out = subprocess.check_output(
            ["gsettings", "get", "org.gnome.desktop.input-sources", "per-window"],
            stderr=subprocess.DEVNULL,
        ).decode().strip().lower()
        return out == "true"
    except Exception:
        return False

t4_chips = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
chk_pw = Gtk.ToggleButton(label="Riêng từng cửa sổ")
chk_pw.set_tooltip_text("Nhớ chế độ bộ gõ riêng cho từng cửa sổ ứng dụng (VD: Terminal tiếng Anh, Trình duyệt tiếng Việt)")
chk_pw.set_active(get_gnome_per_window())
chk_ul = Gtk.ToggleButton(label="Gạch chân")
chk_ul.set_tooltip_text("Bật/tắt đường gạch chân dưới từ đang gõ (mặc định: Tắt)")
chk_ul.set_active(cfg.get("PREEDIT_UNDERLINE", "false") == "true")
t4_chips.pack_start(chk_pw, True, True, 0)
t4_chips.pack_start(chk_ul, False, False, 0)

def on_pw_toggled(btn):
    val = "true" if btn.get_active() else "false"
    try:
        subprocess.Popen(
            ["gsettings", "set", "org.gnome.desktop.input-sources", "per-window", val],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
        )
    except Exception:
        pass

def on_ul_toggled(btn):
    cfg["PREEDIT_UNDERLINE"] = "true" if btn.get_active() else "false"
    save_current_config()

chk_pw.connect("toggled", on_pw_toggled)
chk_ul.connect("toggled", on_ul_toggled)
tile4.pack_start(t4_top, False, False, 0)
tile4.pack_start(t4_chips, False, False, 0)

bento_grid.attach(tile1, 0, 0, 1, 1)
bento_grid.attach(tile2, 1, 0, 1, 1)
bento_grid.attach(tile3, 0, 1, 1, 1)
bento_grid.attach(tile4, 1, 1, 1, 1)
tab_settings.pack_start(bento_grid, False, False, 0)

# Section 3: Compact Smart Engine Status Strip
strip_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
strip_box.get_style_context().add_class("bento-strip")
strip_lbl = Gtk.Label()
strip_lbl.set_markup(
    "<span size='small' weight='bold' foreground='#5856d6'>✦ Trí tuệ Sen Việt tự động:</span> "
    "<span size='small' foreground='#6e6e73'>Song ngữ • Chuẩn mới • Huỷ dấu w/a/e/o • IBus &amp; Fcitx5</span>"
)
strip_lbl.set_xalign(0)
strip_box.pack_start(strip_lbl, True, True, 0)
tab_settings.pack_start(strip_box, False, False, 0)

stack.add_titled(tab_settings, "settings", "Cài đặt")

# ==============================================================================
# TAB 2: VỀ ỨNG DỤNG (Matches macOS aboutTabView + NidoOffice & YouPersona.com)
# ==============================================================================
tab_about = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
tab_about.set_border_width(14)

# Card 1: SỨ MỆNH TỐI THƯỢNG
c_mission = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4)
c_mission.get_style_context().add_class("bento-card")
m_hdr = Gtk.Label()
m_hdr.set_markup("<span size='small' weight='bold' foreground='#5856d6'>✦ SỨ MỆNH TỐI THƯỢNG</span>")
m_hdr.set_xalign(0)
m_body = Gtk.Label(
    label='Sen Việt được phát triển theo kim chỉ nam "Hãy để việc gõ là gõ, dù bạn gõ tiếng Việt hay tiếng Anh; nhanh hay chậm; gõ là Sen Việt".'
)
m_body.set_line_wrap(True)
m_body.set_xalign(0)
c_mission.pack_start(m_hdr, False, False, 0)
c_mission.pack_start(m_body, False, False, 0)
tab_about.pack_start(c_mission, False, False, 0)

# Card 2: VietQR
c_qr = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
c_qr.get_style_context().add_class("bento-card")
qr_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2)
qr_t = Gtk.Label()
qr_t.set_markup("<span weight='bold' foreground='#1c1c1e'>☕ Mời tác giả ly cà phê nhỏ (VietQR)</span>")
qr_t.set_xalign(0)
qr_s = Gtk.Label()
qr_s.set_markup(
    "<span size='small' foreground='#5856d6' weight='bold'>MB Bank • STK: 0979266045</span> "
    "<span size='small' foreground='#6e6e73'>• Chủ TK: Trần Phát Đạt</span>"
)
qr_s.set_xalign(0)
qr_vbox.pack_start(qr_t, False, False, 0)
qr_vbox.pack_start(qr_s, False, False, 0)
btn_copy_stk = Gtk.Button(label="Sao chép STK")
def on_copy_stk(btn):
    try:
        cb = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
        cb.set_text("0979266045", -1)
        btn.set_label("✓ Đã chép")
    except Exception:
        pass
btn_copy_stk.connect("clicked", on_copy_stk)
c_qr.pack_start(qr_vbox, True, True, 0)
c_qr.pack_end(btn_copy_stk, False, False, 0)
tab_about.pack_start(c_qr, False, False, 0)

# Card 3: Ecosystem Showcase — NidoOffice (https://educenter.app) & YouPersona.com
c_eco = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
c_eco.get_style_context().add_class("bento-card")

def make_eco_row(title, badge, badge_color, desc, url):
    row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
    vb = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2)
    lbl_top = Gtk.Label()
    lbl_top.set_markup(
        f"<span weight='bold' foreground='#1c1c1e'>{title}</span>  "
        f"<span size='small' weight='bold' foreground='{badge_color}'>[{badge}]</span>"
    )
    lbl_top.set_xalign(0)
    lbl_sub = Gtk.Label()
    lbl_sub.set_markup(f"<span size='small' foreground='#6e6e73'>{desc}</span>")
    lbl_sub.set_xalign(0)
    vb.pack_start(lbl_top, False, False, 0)
    vb.pack_start(lbl_sub, False, False, 0)
    btn = Gtk.Button(label="Khám phá ↗")
    btn.connect("clicked", lambda *_: webbrowser.open(url))
    row.pack_start(vb, True, True, 0)
    row.pack_end(btn, False, False, 0)
    return row

c_eco.pack_start(
    make_eco_row(
        "NidoOffice",
        "BỘ OFFICE AI • EDUCENTER.APP",
        "#5856d6",
        "Soạn thảo văn bản, bảng tính, thuyết trình &amp; học liệu AI thế hệ mới.",
        "https://educenter.app",
    ),
    False,
    False,
    0,
)
c_eco.pack_start(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL), False, False, 2)
c_eco.pack_start(
    make_eco_row(
        "YouPersona.com",
        "QUẢN LÝ THU CHI AI",
        "#0d9488",
        "Trợ lý Tài chính Cá nhân AI — ghi chép giọng nói, quét hoá đơn &amp; 6 chiếc lọ.",
        "https://youpersona.com",
    ),
    False,
    False,
    0,
)
tab_about.pack_start(c_eco, False, False, 0)

# Card 4: Cộng đồng & Tác giả
c_links = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
c_links.get_style_context().add_class("bento-card")
for lbl_txt, link_url in (
    ("Cộng đồng Zalo ↗", "https://zalo.me/g/6wwyvywyvhsb0n6rwkze"),
    ("Tác giả: Trần Phát Đạt (LinkedIn) ↗", "https://www.linkedin.com/in/stevedat/?isSelfProfile=true"),
    ("Mã nguồn GitHub ↗", "https://github.com/stevedat/VieLotus-IM"),
):
    b = Gtk.Button(label=lbl_txt)
    b.connect("clicked", lambda _b, u=link_url: webbrowser.open(u))
    c_links.pack_start(b, True, True, 0)
tab_about.pack_start(c_links, False, False, 0)

stack.add_titled(tab_about, "about", "Về ứng dụng")
root_vbox.pack_start(stack, True, True, 0)

# 3. Bottom Footer Bar (Matches macOS & Windows footer: Status + NidoOffice • YouPersona.com • Zalo • GitHub)
footer_bar = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
footer_bar.get_style_context().add_class("bento-footer")
f_status = Gtk.Label()
f_status.set_markup(
    "<span foreground='#22c55e'>●</span> "
    "<span size='small' foreground='#6e6e73'>Song ngữ • Chuẩn mới • Tự động lưu</span>"
)
f_status.set_xalign(0)
footer_bar.pack_start(f_status, True, True, 0)

for f_txt, f_url in (
    ("NidoOffice", "https://educenter.app"),
    ("YouPersona.com", "https://youpersona.com"),
    ("Zalo", "https://zalo.me/g/6wwyvywyvhsb0n6rwkze"),
    ("GitHub", "https://github.com/stevedat/VieLotus-IM"),
):
    fb = Gtk.LinkButton.new_with_label(f_url, f_txt)
    footer_bar.pack_start(fb, False, False, 0)

root_vbox.pack_end(footer_bar, False, False, 0)

win.connect("destroy", Gtk.main_quit)
win.show_all()
try:
    win.present()
except Exception:
    pass

if smoke_mode:
    def _smoke_step():
        save_current_config()
        Gtk.main_quit()
        return False
    GLib.timeout_add(150, _smoke_step)

Gtk.main()
GTK_PYEOF
}

case "${1:-}" in
    --activate)
        load_config
        save_and_apply "${INPUT_METHOD}" "1"
        echo "✅ Đã kích hoạt bộ gõ Sen Việt (${INPUT_METHOD}) cho cả Fcitx5 và IBus."
        exit 0
        ;;
    --telex)
        load_config
        save_and_apply "telex" "1"
        echo "✅ Đã chuyển Sen Việt sang kiểu gõ Telex (Fcitx5 & IBus)."
        exit 0
        ;;
    --vni)
        load_config
        save_and_apply "vni" "1"
        echo "✅ Đã chuyển Sen Việt sang kiểu gõ VNI (Fcitx5 & IBus)."
        exit 0
        ;;
    --status)
        load_config
        echo "INPUT_METHOD=${INPUT_METHOD}"
        echo "GRAMMAR_PROFILE=${GRAMMAR_PROFILE}"
        echo "SMART_BILINGUAL=${SMART_BILINGUAL}"
        echo "MODERN_ORTHOGRAPHY=${MODERN_ORTHOGRAPHY}"
        echo "QUICK_TELEX=${QUICK_TELEX}"
        echo "RELAXED_CODA=${RELAXED_CODA}"
        echo "MACRO_ENABLED=${MACRO_ENABLED}"
        echo "DEVELOPER_MODE=${DEVELOPER_MODE}"
        echo "PREEDIT_UNDERLINE=${PREEDIT_UNDERLINE}"
        exit 0
        ;;
    --smoke-test-gui)
        load_config
        run_gtk_settings "1"
        echo "✅ GTK3 Settings GUI smoke test PASSED."
        exit 0
        ;;
esac

# Ensure graphical session variables are discovered if launched from a minimal desktop/terminal context
UID_CUR="$(id -u 2>/dev/null || echo 1000)"
if [ -z "${XDG_RUNTIME_DIR:-}" ] && [ -d "/run/user/${UID_CUR}" ]; then
    export XDG_RUNTIME_DIR="/run/user/${UID_CUR}"
fi
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ] && [ -S "/run/user/${UID_CUR}/bus" ]; then
    export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/${UID_CUR}/bus"
fi
if [ -z "${WAYLAND_DISPLAY:-}" ] && [ -S "/run/user/${UID_CUR}/wayland-0" ]; then
    export WAYLAND_DISPLAY="wayland-0"
fi
if [ -z "${DISPLAY:-}" ] && [ -S "/tmp/.X11-unix/X0" ]; then
    export DISPLAY=":0"
fi

# Load current configuration without mutating any system or user files on startup
load_config

# Launch Native GTK3 Desktop Settings Window if graphical session is available
if command -v python3 >/dev/null 2>&1 && [ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]; then
    if run_gtk_settings "0" 2>"${LOG_FILE}"; then
        exit 0
    fi
    # Fallback to Python Tkinter GUI if python3-gi is not installed
    if python3 - "${CONFIG_FILE}" <<'TK_PYEOF' 2>>"${LOG_FILE}"; then
import os, subprocess, sys
import tkinter as tk
from tkinter import ttk

config_path = sys.argv[1]
cfg = {
    "INPUT_METHOD": "telex",
    "GRAMMAR_PROFILE": "sen_flex",
    "SMART_BILINGUAL": "true",
    "MODERN_ORTHOGRAPHY": "true",
    "QUICK_TELEX": "false",
    "RELAXED_CODA": "false",
    "MACRO_ENABLED": "true",
    "DEVELOPER_MODE": "false",
    "PREEDIT_UNDERLINE": "false",
}
if os.path.exists(config_path):
    with open(config_path, "r", encoding="utf-8", errors="ignore") as f:
        for line in f:
            if "=" in line and not line.lstrip().startswith("#"):
                k, v = line.strip().split("=", 1)
                cfg[k.strip()] = v.strip().strip('"').strip("'")

root = tk.Tk()
root.title("Sen Việt (VieLotusIM v2.0.1) — Cài đặt")
root.geometry("460x320")
root.resizable(False, False)

im_var = tk.StringVar(value=cfg.get("INPUT_METHOD", "telex"))
qt_var = tk.BooleanVar(value=cfg.get("QUICK_TELEX", "false") == "true")
rc_var = tk.BooleanVar(value=cfg.get("RELAXED_CODA", "false") == "true")
mc_var = tk.BooleanVar(value=cfg.get("MACRO_ENABLED", "true") == "true")
dv_var = tk.BooleanVar(value=cfg.get("DEVELOPER_MODE", "false") == "true")

def apply_changes(*_):
    cfg["INPUT_METHOD"] = im_var.get()
    cfg["QUICK_TELEX"] = "true" if qt_var.get() else "false"
    cfg["RELAXED_CODA"] = "true" if rc_var.get() else "false"
    cfg["MACRO_ENABLED"] = "true" if mc_var.get() else "false"
    cfg["DEVELOPER_MODE"] = "true" if dv_var.get() else "false"
    os.makedirs(os.path.dirname(config_path), exist_ok=True)
    with open(config_path, "w", encoding="utf-8") as f:
        for k, v in cfg.items():
            f.write(f'{k}="{v}"\n')
    im_flag = "--vni" if cfg["INPUT_METHOD"] == "vni" else "--telex"
    subprocess.Popen(["/usr/bin/vielotus-settings", im_flag], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

frm = ttk.Frame(root, padding=16)
frm.pack(fill="both", expand=True)
ttk.Label(frm, text="🌸 Sen Việt (VieLotusIM v2.0.1)", font=("Sans", 13, "bold")).pack(anchor="w")
ttk.Label(frm, text="Kiểu gõ Tiếng Việt (tự động lưu & áp dụng):").pack(anchor="w", pady=(10, 4))
ttk.Radiobutton(frm, text="Telex Tự Do (s f r x j w — vieetj → việt)", variable=im_var, value="telex", command=apply_changes).pack(anchor="w")
ttk.Radiobutton(frm, text="VNI Chuẩn (phím số 1–9 — vie65t → việt)", variable=im_var, value="vni", command=apply_changes).pack(anchor="w")
ttk.Separator(frm, orient="horizontal").pack(fill="x", pady=10)
ttk.Checkbutton(frm, text="Gõ tắt phụ âm (Quick Telex: cc=ch, gg=gi, kk=kh)", variable=qt_var, command=apply_changes).pack(anchor="w")
ttk.Checkbutton(frm, text="Phụ âm cuối mở rộng (f, j, w, z)", variable=rc_var, command=apply_changes).pack(anchor="w")
ttk.Checkbutton(frm, text="Gõ tắt thông minh (vn → Việt Nam)", variable=mc_var, command=apply_changes).pack(anchor="w")
ttk.Checkbutton(frm, text="Bảo vệ Code & Terminal (IDE / CLI)", variable=dv_var, command=apply_changes).pack(anchor="w")
root.mainloop()
TK_PYEOF
        exit 0
    fi
fi

if command -v zenity >/dev/null 2>&1 && [ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]; then
    TELEX_TRUE="TRUE"
    VNI_TRUE="FALSE"
    if [ "${INPUT_METHOD}" = "vni" ]; then
        TELEX_TRUE="FALSE"
        VNI_TRUE="TRUE"
    fi
    CHOICE=$(zenity --list --radiolist \
        --title="Sen Việt (VieLotusIM) — Cài đặt bộ gõ" \
        --text="Bộ gõ tiếng Việt Sen Việt đã được kích hoạt cho Fcitx5 & IBus.\nChọn kiểu gõ mặc định:" \
        --width=460 --height=260 \
        --column="Chọn" --column="Mã" --column="Kiểu gõ tiếng Việt" \
        "${TELEX_TRUE}" "telex" "Telex (Gõ dấu tự do SEN Flex & Song ngữ thông minh)" \
        "${VNI_TRUE}" "vni" "VNI (Gõ dấu bằng phím số 1–9)" \
        --hide-column=2 2>/dev/null || true)
    if [ -n "${CHOICE}" ]; then
        save_and_apply "${CHOICE}"
        zenity --notification --text="Sen Việt: Đã kích hoạt kiểu gõ $(echo "${CHOICE}" | tr 'a-z' 'A-Z')" 2>/dev/null || true
    fi
    exit 0
fi

echo "🌸 === Sen Việt (VieLotusIM) cho Linux (Fcitx5 & IBus) ==="
echo "Trạng thái: Đã kích hoạt (${INPUT_METHOD})"
echo "  • Chuyển sang Telex : vielotus --telex"
echo "  • Chuyển sang VNI   : vielotus --vni"
echo "  • Kiểm tra cấu hình : vielotus --status"
echo "  • Khởi động lại Fcitx5: fcitx5 -r -d"
