#!/usr/bin/env bash

BIN_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
if [ -z "$SERPANTINUM_DIR" ]; then
    export SERPANTINUM_DIR="$(dirname "$BIN_DIR")/src"
fi

source "$SERPANTINUM_DIR/scripts/caching.sh"
source "$SERPANTINUM_DIR/scripts/config.sh"
source "$SERPANTINUM_DIR/scripts/i18n.sh"

if [ -z "$MAIN_QML" ]; then
    export MAIN_QML="$(find "$SERPANTINUM_DIR/quickshell" -type f \( -name "Shell.qml" -o -name "Bar.qml" \) 2>/dev/null | head -n 1)"
fi

is_alive() {
    local pid="$1"
    [ -n "$pid" ] || return 1
    kill -0 "$pid" 2>/dev/null || return 1
    local stat
    stat=$(<"/proc/$pid/stat") 2>/dev/null || return 1
    [[ "$stat" =~ \)\ Z ]] && return 1
    return 0
}

terminate_and_wait() {
    local pid="$1"
    local timeout="${2:-2}"
    local count=0
    local max_count=$(( timeout * 20 ))

    if [ -z "$pid" ] || ! is_alive "$pid"; then
        return 0
    fi

    kill -TERM "$pid" 2>/dev/null

    while is_alive "$pid"; do
        if [ "$count" -ge "$max_count" ]; then
            kill -KILL "$pid" 2>/dev/null
            break
        fi
        sleep 0.05
        ((count++))
    done
}

get_installed_version() {
    local version_file="${XDG_STATE_HOME:-$HOME/.local/state}/serpantinum/version"
    local ver=""
    if [ -f "$version_file" ]; then
        ver=$(awk -F= '/^SERPANTINUM_VERSION=/{gsub(/["'\'' ]/, "", $2); print $2}' "$version_file")
    fi
    if [ -z "$ver" ] && [ -n "$SERPANTINUM_VERSION" ]; then
        ver="$SERPANTINUM_VERSION"
    fi
    if [ -z "$ver" ]; then
        if [ -n "$SERPANTINUM_DIR" ] && [ -f "$SERPANTINUM_DIR/version.txt" ]; then
            ver=$(cat "$SERPANTINUM_DIR/version.txt" 2>/dev/null | xargs)
        elif [ -f "$(dirname "$BIN_DIR")/version.txt" ]; then
            ver=$(cat "$(dirname "$BIN_DIR")/version.txt" 2>/dev/null | xargs)
        elif [ -n "$SERPANTINUM_DIR" ] && [ -f "$(dirname "$SERPANTINUM_DIR")/version.txt" ]; then
            ver=$(cat "$(dirname "$SERPANTINUM_DIR")/version.txt" 2>/dev/null | xargs)
        fi
    fi
    if [ -z "$ver" ]; then
        ver="2.0.0"
    fi
    echo "$ver"
}

current_lang_setting="$(get_setting "general" '{}' | jq -r '.language // empty')"
if [ -z "$current_lang_setting" ]; then
    env_lang="${LANGUAGE:-${LANG:-en}}"
    env_lang_short="${env_lang:0:2}"
    current_general="$(get_setting "general" '{}')"
    new_general="$(printf '%s' "$current_general" | jq -c --arg lang "$env_lang_short" '. + {language: $lang}')"
    set_setting "general" "$new_general"
fi

show_help() {
    echo "$(t "cli.usage")"
    echo ""
    echo "$(t "cli.description")"
    echo ""
    echo "$(t "cli.commands")"
    echo "  launch <target> [args...]   $(t "cli.launch_desc")"
    echo "  settings [tab]               $(t "cli.settings_desc")"
    echo "  msg <action|workspace> ...  $(t "cli.msg_desc")"
    echo "  ipc ...                      $(t "cli.ipc_desc")"
    echo "  kill                         $(t "cli.kill_desc")"
    echo "  restart                      $(t "cli.restart_desc")"
    echo "  config <action> [args]       $(t "cli.config_desc")"
    echo "  info <topic>                 $(t "cli.info_desc")"
    echo "  set <topic> [value]          $(t "cli.set_desc")"
    echo "  trigger <action> [args]      $(t "cli.trigger_desc")"
    echo ""
    echo "$(t "cli.script_commands")"
    echo "  exit                         $(t "cli.scripts.exit")"
    echo "  lock                         $(t "cli.scripts.lock")"
    echo "  suspend                      $(t "cli.scripts.suspend")"
    echo "  hibernate                    $(t "cli.scripts.hibernate")"
    echo "  reboot                       $(t "cli.scripts.reboot")"
    echo "  poweroff                     $(t "cli.scripts.poweroff")"
    echo "  redactor [monitor] [widget]  $(t "cli.scripts.redactor")"
    echo "  lock-redactor [action]       $(t "cli.scripts.lock_redactor")"
    echo "  volume                       $(t "cli.scripts.volume")"
    echo "  reload                       $(t "cli.scripts.reload")"
    echo "  weather                      $(t "cli.scripts.weather")"
    echo "  location                     $(t "cli.scripts.location")"
    echo "  screenshot                   $(t "cli.scripts.screenshot")"
    echo "  brightness                   $(t "cli.scripts.brightness")"
    echo "  current_focus                $(t "cli.scripts.current_focus")"
    echo "  monitors_detect              $(t "cli.scripts.monitors_detect")"
    echo "  location_manual              $(t "cli.scripts.location_manual")"
    echo "  blue_light_filter            $(t "cli.scripts.blue_light_filter")"
    echo ""
    echo "$(t "cli.options")"
    echo "  -v, --verbose                $(t "cli.verbose_desc")"
    echo "  -V, --version                $(t "cli.version_desc")"
    echo "  -h, --help                   $(t "cli.help_desc")"
    echo ""
    echo "$(t "cli.examples")"
    echo "  serpantinum launch start"
    echo "  serpantinum settings theme"
    echo "  serpantinum msg workspace 1"
    echo "  serpantinum msg workspace 2 move"
    echo "  serpantinum msg open network wifi"
    echo "  serpantinum msg toggle launcher"
    echo "  serpantinum msg toggle clipboard"
    echo "  serpantinum weather --current-temp"
    echo "  serpantinum kill"
    echo "  serpantinum restart"
    echo ""
}

show_launch_help() {
    echo "$(t "cli.launch_help.usage")"
    echo ""
    echo "$(t "cli.launch_help.description")"
    echo ""
    echo "$(t "cli.launch_help.available_targets")"
    echo "  start            $(t "cli.launch_help.target_start")"
    echo ""
    echo "$(t "cli.options")"
    echo "  -h, --help      $(t "cli.help_desc")"
    echo ""
}

show_msg_help() {
    echo "$(t "cli.msg_help.usage")"
    echo ""
    echo "$(t "cli.msg_help.description")"
    echo ""
    echo "$(t "cli.msg_help.available_commands")"
    echo "  workspace <num> [move]   $(t "cli.msg_help.cmd_workspace")"
    echo "  open <target> [sub]      $(t "cli.msg_help.cmd_open")"
    echo "  toggle <target> [sub]    $(t "cli.msg_help.cmd_toggle")"
    echo "  close                    $(t "cli.msg_help.cmd_close")"
    echo ""
    echo "$(t "cli.options")"
    echo "  -h, --help               $(t "cli.help_desc")"
    echo ""
}

show_ipc_help() {
    echo "$(t "cli.ipc_help.usage")"
    echo ""
    echo "$(t "cli.ipc_help.description")"
    echo ""
    echo "$(t "cli.options")"
    echo "  -h, --help               $(t "cli.help_desc")"
    echo ""
}

ensure_daemon() {
    local pid=""
    if [ -f "/tmp/serpantinumd.pid" ]; then
        pid="$(cat "/tmp/serpantinumd.pid" 2>/dev/null)"
    fi

    if [ -z "$pid" ] || ! is_alive "$pid"; then
        rm -f "/tmp/serpantinumd.pid" 2>/dev/null
        rm -f "/tmp/serpantinumd.lock" 2>/dev/null

        [ "$VERBOSE" = true ] && echo "$(t "cli.starting_daemon")"
        "$BIN_DIR/serpantinumd" start > /dev/null 2>&1 &

        local count=0
        while [ "$count" -lt 15 ]; do
            if [ -f "/tmp/serpantinumd.pid" ] && is_alive "$(cat "/tmp/serpantinumd.pid" 2>/dev/null)"; then
                break
            fi
            sleep 0.1
            ((count++))
        done
    fi
}

VERBOSE=false

while [[ "$1" == -* ]]; do
    case "$1" in
        -v|--verbose)
            VERBOSE=true
            export SERPANTINUM_VERBOSE=true
            shift
            ;;
        -V|--version)
            echo "serpantinum v$(get_installed_version)"
            exit 0
            ;;
        -h|--help)
            show_help
            exit 0
            ;;
        *)
            break
            ;;
    esac
done

if [ $# -eq 0 ]; then
    show_help
    exit 0
fi

stop_daemon() {
    local pid=""
    if [ -f "/tmp/serpantinumd.pid" ]; then
        pid="$(cat "/tmp/serpantinumd.pid" 2>/dev/null)"
    fi

    if [ -n "$pid" ] && is_alive "$pid"; then
        terminate_and_wait "$pid" 3
    else
        pkill -TERM -f "focus_daemon.py" 2>/dev/null
        if [ -n "$MAIN_QML" ]; then
            pkill -TERM -f "quickshell.*$MAIN_QML" 2>/dev/null
        fi
        sleep 0.2
    fi

    pkill -KILL -f "focus_daemon.py" 2>/dev/null
    if [ -n "$MAIN_QML" ]; then
        pkill -KILL -f "quickshell.*$MAIN_QML" 2>/dev/null
    fi

    rm -f "/tmp/serpantinumd.pid" 2>/dev/null
    rm -f "/tmp/serpantinumd.lock" 2>/dev/null
}

cli_usage() {
    echo "$(t "cli.usage_label") serpantinum $*" >&2
    exit 1
}

cli_ipc() {
    ensure_daemon
    quickshell -p "$MAIN_QML" ipc call "$@"
}

cli_lock_redactor() {
    local action="${1:-toggle}"
    case "$action" in
        toggle|close) cli_ipc lock-redactor "$action" ;;
        open) cli_ipc lock-redactor open "${2:-}" ;;
        *) cli_usage "lock-redactor [toggle|open [monitor]|close]" ;;
    esac
}

cli_cfg_apply() {
    local filter="$1"
    shift
    _config_ensure_settings
    local tmp="${CONFIG_SETTINGS_JSON}.tmp"
    if jq "$@" "$filter" "$CONFIG_SETTINGS_JSON" > "$tmp" 2>/dev/null && jq . "$tmp" >/dev/null 2>&1; then
        mv "$tmp" "$CONFIG_SETTINGS_JSON"
    else
        rm -f "$tmp"
        return 1
    fi
}

cli_cfg_get() {
    _config_ensure_settings
    jq -r --arg p "$1" --arg f "${2:-}" \
        '(try getpath($p | split(".")) catch null) as $v | if $v == null then $f elif ($v | type) == "string" then $v else ($v | tojson) end' \
        "$CONFIG_SETTINGS_JSON"
}

cli_cfg_set() {
    local value
    if [ -n "$2" ] && printf '%s' "$2" | jq . >/dev/null 2>&1; then
        value="$2"
    else
        value="$(jq -Rn --arg v "$2" '$v')"
    fi
    cli_cfg_apply 'setpath($p | split("."); $v)' --arg p "$1" --argjson v "$value"
}

cli_config() {
    local sub="${1:-}"
    case "$sub" in
        get)
            [ -n "$2" ] || cli_usage "config get <key> [fallback]"
            cli_cfg_get "$2" "${3:-}"
            ;;
        set)
            [ $# -ge 3 ] || cli_usage "config set <key> <value>"
            cli_cfg_set "$2" "$3"
            ;;
        dump)
            _config_ensure_settings
            jq . "$CONFIG_SETTINGS_JSON"
            ;;
        path)
            _config_ensure_settings
            echo "$CONFIG_SETTINGS_JSON"
            ;;
        edit)
            _config_ensure_settings
            local -a editor
            read -ra editor <<< "${VISUAL:-${EDITOR:-vi}}"
            "${editor[@]}" "$CONFIG_SETTINGS_JSON"
            ;;
        *)
            cli_usage "config <get <key> [fallback]|set <key> <value>|dump|path|edit>"
            ;;
    esac
}

cli_switch() {
    local path="$1"
    local action="${2:-toggle}"
    local default="$3"
    local label="$4"
    local current new
    current="$(cli_cfg_get "$path" "$default")"

    case "$action" in
        on) new=true ;;
        off) new=false ;;
        toggle) [ "$current" = "true" ] && new=false || new=true ;;
        status) new="$current" ;;
        *) cli_usage "$label <on|off|toggle|status>" ;;
    esac

    if [[ "$action" != "status" ]]; then
        cli_cfg_set "$path" "$new"
    fi

    [ "$new" = "true" ] && echo "$(t "cli.state_on")" || echo "$(t "cli.state_off")"
}

cli_wallpaper_files() {
    local dir
    dir="$(cli_cfg_get wallpaperDir "")"
    [ -n "$dir" ] || dir="$(cli_cfg_get wallpaper_dir "")"
    [ -n "$dir" ] || dir="${WALLPAPER_DIR:-$HOME/Pictures/Wallpapers}"
    [ -d "$dir" ] || return 0
    find "$dir" -maxdepth 1 -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.webp" -o -iname "*.gif" -o -iname "*.mp4" -o -iname "*.mkv" -o -iname "*.mov" -o -iname "*.webm" \) | sort
}

cli_theme_find() {
    local file name
    for file in "$SERPANTINUM_DIR"/assets/themes/*.json; do
        name="$(basename "$file" .json)"
        if [[ "${name,,}" == "${1,,}" ]]; then
            echo "$file"
            return 0
        fi
    done
    return 1
}

cli_monitors() {
    local script="$SERPANTINUM_DIR/scripts/monitors_detect.sh"
    if [[ "$1" == "--json" ]]; then
        "$script" --verbose | jq -Rn '[inputs | split("|") | (.[1] | split("x")) as $res | {name: .[0], width: ($res[0] | tonumber? // null), height: ($res[1] | tonumber? // null), refreshRate: (.[2] | tonumber? // null)}]'
    else
        "$script"
    fi
}

cli_check_updates() {
    local out
    out="$(python3 "$SERPANTINUM_DIR/scripts/updater.py")"
    [ -n "$out" ] || exit 1
    if [[ "$1" == "--json" ]]; then
        echo "$out"
        return
    fi
    local local_ver remote_ver
    local_ver="$(jq -r '.local' <<< "$out")"
    remote_ver="$(jq -r '.remote' <<< "$out")"
    if [ "$(jq -r '.has_update' <<< "$out")" = "true" ]; then
        echo "$(t "cli.update_available" LOCAL="$local_ver" REMOTE="$remote_ver")"
    else
        echo "$(t "cli.up_to_date" VERSION="$local_ver")"
    fi
}

cli_caffeine() {
    cli_switch idle.manualInhibit "$1" false "set idle caffeine"
    if [[ "${1:-toggle}" != "status" && "$(cli_cfg_get idle.manualInhibit false)" != "true" ]]; then
        cli_cfg_apply '.idle = ((.idle // {}) + {caffeineStartTime: 0, caffeineEndTime: 0})'
    fi
}

cli_matugen() {
    local current mode
    current="$(cli_cfg_get theme.matugen true)"
    case "${1:-toggle}" in
        on) mode=true ;;
        off) mode=false ;;
        toggle) [ "$current" = "true" ] && mode=false || mode=true ;;
        *) cli_usage "set theme matugen [on|off|toggle]" ;;
    esac
    if [ "$mode" = true ]; then
        cli_cfg_apply '.theme = ((.theme // {}) + {activePreset: "Matugen", matugen: true})'
        cli_ipc matugen generateImage "$(cli_ipc wallpaper getWallpaperPath "")"
    else
        cli_cfg_apply '.theme = ((.theme // {}) + {matugen: false})'
    fi
    cli_ipc theme reloadColors
}

cli_set_theme() {
    local file name colors mode
    [ -n "$1" ] || cli_usage "set theme preset <name>"
    if ! file="$(cli_theme_find "$1")"; then
        echo "$(t "cli.error_unknown_theme" NAME="$1")" >&2
        exit 1
    fi
    name="$(jq -r '.name // empty' "$file")"
    [ -n "$name" ] || name="$(basename "$file" .json)"
    colors="$(jq -c '.colors' "$file")"
    mode="$(cli_cfg_get theme.mode dark)"
    cli_cfg_apply '.theme = ((.theme // {}) + {activePreset: $n, matugen: false, colors: $c})' --arg n "$name" --argjson c "$colors"
    cli_ipc matugen generateFromStatic "$colors" "$mode"
    cli_ipc theme reloadColors
}

cli_app_theme() {
    local id="$1" listing current next enabled
    local engine="$SERPANTINUM_DIR/scripts/theming/apptheme.py"
    [ -n "$id" ] || cli_usage "set theme app <id> [on|off|toggle]"
    export QS_STATE_DIR="${QS_STATE_DIR:-$HOME/.local/state/serpantinum}" QS_SETTINGS="$CONFIG_SETTINGS_JSON"
    listing="$(python3 "$engine" list)" || exit 1
    if ! jq -e --arg i "$id" '.apps | any(.id == $i)' <<< "$listing" >/dev/null; then
        echo "$(t "cli.error_unknown_app" ID="$id")" >&2
        exit 1
    fi
    current="$(jq -r --arg i "$id" '.apps[] | select(.id == $i) | .enabled' <<< "$listing")"
    case "${2:-toggle}" in
        on) next=true ;;
        off) next=false ;;
        toggle) [ "$current" = "true" ] && next=false || next=true ;;
        *) cli_usage "set theme app <id> [on|off|toggle]" ;;
    esac
    enabled="$(jq -c --arg i "$id" --argjson on "$next" '[.apps[] | select(.enabled and .id != $i) | .id] + (if $on then [$i] else [] end) | sort' <<< "$listing")"
    cli_cfg_apply '.theme = ((.theme // {}) + {apps: $a})' --argjson a "$enabled"
    python3 "$engine" apply --enabled="$(jq -r 'join(",")' <<< "$enabled")" >/dev/null || true
}

cli_set_lang() {
    [ -n "$1" ] || cli_usage "set lang <code>"
    if [ ! -f "$I18N_DIR/$1.json" ]; then
        echo "$(t "cli.error_unknown_language" CODE="$1")" >&2
        exit 1
    fi
    cli_cfg_set general.language "$1"
}

cli_set_wallpaper() {
    local value="${1:-}"
    local screen="${2:-all}"
    local target current files
    case "$value" in
        "")
            cli_usage "set wallpaper <path|random|next|prev|play|pause|clear> [screen]"
            ;;
        random|next|prev)
            files="$(cli_wallpaper_files)"
            if [ -z "$files" ]; then
                echo "$(t "cli.error_no_wallpapers")" >&2
                exit 1
            fi
            if [[ "$value" == "random" ]]; then
                target="$(shuf -n 1 <<< "$files")"
            else
                current="$(cli_ipc wallpaper getWallpaperPath "$([ "$screen" = all ] && echo "" || echo "$screen")")"
                target="$(awk -v cur="$current" -v dir="$value" '
                    function base(p,  a, n) { n = split(p, a, "/"); return a[n] }
                    { f[NR] = $0; if (base($0) == base(cur)) idx = NR }
                    END {
                        if (!idx) { print ((dir == "next") ? f[1] : f[NR]); exit }
                        print f[(dir == "next") ? idx % NR + 1 : (idx + NR - 2) % NR + 1]
                    }' <<< "$files")"
            fi
            cli_ipc wallpaper setWallpaper "$screen" "$target" ""
            ;;
        play|pause)
            cli_ipc wallpaper setPlayback "$screen" "$value"
            ;;
        clear)
            cli_ipc wallpaper clearWallpaper "$screen"
            ;;
        *)
            if [ ! -f "$value" ]; then
                echo "$(t "cli.error_file_not_found" PATH="$value")" >&2
                exit 1
            fi
            cli_ipc wallpaper setWallpaper "$screen" "$(realpath "$value")" "${3:-}"
            ;;
    esac
}

cli_settings_json() {
    _config_ensure_settings
    jq -c "$@" "$CONFIG_SETTINGS_JSON"
}

cli_list_json() {
    local file
    for file in "$@"; do
        [ -f "$file" ] && basename "$file" .json
    done | jq -Rsc 'split("\n") | map(select(length > 0))'
}

cli_info_group() {
    local json
    case "$1" in
        notifications) json="$(cli_settings_json '{dnd: (.notifications.dnd == true)}')" ;;
        idle) json="$(cli_ipc idle status)" ;;
        dock) json="$(cli_settings_json '{enabled: (.dock.enabled != false), autohide: (.dock.autohide == true)}')" ;;
        sfx) json="$(cli_settings_json '{mute: (.general.muteSfx == true)}')" ;;
        theme)
            json="$(cli_settings_json --argjson p "$(cli_list_json "$SERPANTINUM_DIR"/assets/themes/*.json)" \
                '{preset: (.theme.activePreset // "Matugen"), matugen: (.theme.matugen != false), apps: (.theme.apps // ["cava", "gtk", "kitty", "qt"]), presets: $p}')"
            ;;
        lang)
            json="$(jq -nc --arg c "$(get_current_language)" --argjson a "$(cli_list_json "$I18N_DIR"/*.json)" \
                '{current: $c, available: $a}')"
            ;;
    esac
    if [ -z "$2" ]; then
        jq . <<< "$json"
    elif jq -e --arg k "$2" 'has($k)' <<< "$json" >/dev/null 2>&1; then
        jq -r --arg k "$2" '.[$k] | if type == "array" then .[] else . end' <<< "$json"
    else
        cli_usage "info $1 [$(jq -r 'keys_unsorted | join("|")' <<< "$json")]"
    fi
}

cli_info() {
    local topic="${1:-}"
    case "$topic" in
        notifications|idle|dock|sfx|theme|lang) cli_info_group "$topic" "${2:-}" ;;
        wallpaper) cli_ipc wallpaper getWallpaperPath "${2:-}" ;;
        monitors) cli_monitors "$2" ;;
        updates) cli_check_updates "$2" ;;
        *) cli_usage "info <notifications|idle|dock|sfx|theme|lang> [key] | info <wallpaper [screen]|monitors [--json]|updates [--json]>" ;;
    esac
}

cli_set() {
    local group="${1:-}" key="${2:-}"
    case "$group" in
        notifications)
            case "$key" in
                dnd) cli_switch notifications.dnd "$3" false "set notifications dnd" ;;
                *) cli_usage "set notifications dnd [on|off|toggle]" ;;
            esac
            ;;
        idle)
            case "$key" in
                caffeine) cli_caffeine "$3" ;;
                *) cli_usage "set idle caffeine [on|off|toggle]" ;;
            esac
            ;;
        dock)
            case "$key" in
                enabled) cli_switch dock.enabled "$3" true "set dock enabled" ;;
                autohide) cli_switch dock.autohide "$3" false "set dock autohide" ;;
                *) cli_usage "set dock <enabled|autohide> [on|off|toggle]" ;;
            esac
            ;;
        sfx)
            case "$key" in
                mute) cli_switch general.muteSfx "$3" false "set sfx mute" ;;
                *) cli_usage "set sfx mute [on|off|toggle]" ;;
            esac
            ;;
        theme)
            case "$key" in
                preset) cli_set_theme "$3" ;;
                matugen) cli_matugen "$3" ;;
                app) cli_app_theme "$3" "$4" ;;
                *) cli_usage "set theme <preset <name>|matugen [on|off|toggle]|app <id> [on|off|toggle]>" ;;
            esac
            ;;
        lang) cli_set_lang "$2" ;;
        wallpaper)
            shift
            cli_set_wallpaper "$@"
            ;;
        *) cli_usage "set <notifications dnd|idle caffeine|dock <enabled|autohide>|sfx mute> [on|off|toggle] | set theme <preset <name>|matugen [on|off|toggle]|app <id> [on|off|toggle]> | set lang <code> | set wallpaper <value> [screen]" ;;
    esac
}

cli_trigger() {
    case "${1:-}" in
        idle)
            case "${2:-}" in
                dim|dpms|lock|suspend) cli_ipc idle trigger "$2" ;;
                *) cli_usage "trigger idle <dim|dpms|lock|suspend>" ;;
            esac
            ;;
        notifications)
            case "${2:-}" in
                clear) cli_ipc main clearNotifications ;;
                *) cli_usage "trigger notifications clear" ;;
            esac
            ;;
        firstlaunch)
            case "${2:-}" in
                trigger|reset) cli_ipc firstlaunch "$2" ;;
                *) cli_usage "trigger firstlaunch <trigger|reset>" ;;
            esac
            ;;
        theme)
            case "${2:-}" in
                reload) cli_ipc theme reloadColors ;;
                generate)
                    [ -n "$3" ] || cli_usage "trigger theme generate <image> [mode] [scheme]"
                    if [ ! -f "$3" ]; then
                        echo "$(t "cli.error_file_not_found" PATH="$3")" >&2
                        exit 1
                    fi
                    cli_ipc matugen generate "$(realpath "$3")" "${4:-}" "${5:-}"
                    ;;
                *) cli_usage "trigger theme <reload|generate <image> [mode] [scheme]>" ;;
            esac
            ;;
        *)
            cli_usage "trigger <idle <dim|dpms|lock|suspend>|notifications clear|firstlaunch <trigger|reset>|theme <reload|generate <image> [mode] [scheme]>>"
            ;;
    esac
}

if [[ "$1" == "kill" ]]; then
    stop_daemon
    echo "$(t "cli.daemon_stopped")"
    exit 0
fi

if [[ "$1" == "restart" ]]; then
    stop_daemon
    ensure_daemon
    echo "$(t "cli.daemon_restarted")"
    exit 0
fi

if [[ "$1" == "launch" ]]; then
    if [[ "$2" == "-h" || "$2" == "--help" ]]; then
        show_launch_help
        exit 0
    fi
    if [ -z "$2" ]; then
        echo "$(t "cli.error_missing_qml")"
        echo "$(t "cli.launch_usage")"
        exit 1
    fi

    TARGET="$(printf '%s' "$2" | tr '[:upper:]' '[:lower:]')"
    case "$TARGET" in
        start)
            QML_NAME="Start"
            ;;
        *)
            echo "$(t "cli.error_unknown_target" TARGET="$2")"
            show_launch_help
            exit 1
            ;;
    esac

    shift 2
    export SERPANTINUM_LAUNCH_ARGS="$*"

    QML_FILE=$(find "$SERPANTINUM_DIR/quickshell" -type f -name "${QML_NAME}.qml" 2>/dev/null | head -n 1)

    if [ -n "$QML_FILE" ]; then
        ensure_daemon
        export SERPANTINUM_TARGET_FILE="$QML_FILE"
        exec quickshell -p "$SERPANTINUM_DIR/quickshell/Runner.qml"
    else
        echo "$(t "cli.error_qml_not_found" NAME="${QML_NAME}" DIR="$SERPANTINUM_DIR/quickshell/")"
        exit 1
    fi
fi

if [[ "$1" == "lock-redactor" ]]; then
    shift
    cli_lock_redactor "$@"
    exit $?
fi

if [[ "$1" == "settings" ]]; then
    shift
    exec "$SERPANTINUM_DIR/scripts/settings.sh" "$@"
fi

if [[ "$1" == "msg" ]]; then
    if [[ "$2" == "-h" || "$2" == "--help" || -z "$2" ]]; then
        show_msg_help
        exit 0
    fi
    ensure_daemon
    shift
    if [[ "$1" == "workspace" ]]; then
        shift
    fi
    exec "$SERPANTINUM_DIR/scripts/qs_manager.sh" "$@"
fi

if [[ "$1" == "ipc" ]]; then
    if [[ "$2" == "-h" || "$2" == "--help" ]]; then
        show_ipc_help
        exit 0
    fi

    ensure_daemon

    SHELL_QML=$(find "$SERPANTINUM_DIR/quickshell" -type f -name "Shell.qml" 2>/dev/null | head -n 1)

    if [ -z "$SHELL_QML" ] && [ -n "$MAIN_QML" ]; then
        SHELL_QML="$MAIN_QML"
    fi

    if [ -z "$SHELL_QML" ]; then
        echo "$(t "cli.error_shell_qml_not_found" DIR="$SERPANTINUM_DIR/quickshell/")"
        exit 1
    fi

    shift
    exec quickshell -p "$SHELL_QML" ipc "$@"
fi

case "$1" in
    config)
        shift
        cli_config "$@"
        exit $?
        ;;
    info)
        shift
        cli_info "$@"
        exit $?
        ;;
    set)
        shift
        cli_set "$@"
        exit $?
        ;;
    trigger)
        shift
        cli_trigger "$@"
        exit $?
        ;;
esac

ALLOWED_SCRIPTS=(
    "exit"
    "lock"
    "suspend"
    "hibernate"
    "reboot"
    "poweroff"
    "redactor"
    "volume"
    "reload"
    "weather"
    "location"
    "screenshot"
    "brightness"
    "current_focus"
    "monitors_detect"
    "location_manual"
    "blue_light_filter"
)

COMMAND="$1"
IS_ALLOWED=false
for s in "${ALLOWED_SCRIPTS[@]}"; do
    if [[ "$COMMAND" == "$s" ]]; then
        IS_ALLOWED=true
        break
    fi
done

SCRIPT_PATH="$SERPANTINUM_DIR/scripts/${COMMAND}.sh"
if [ ! -f "$SCRIPT_PATH" ] && [ -f "$SERPANTINUM_DIR/scripts/system/${COMMAND}.sh" ]; then
    SCRIPT_PATH="$SERPANTINUM_DIR/scripts/system/${COMMAND}.sh"
fi

if [ "$IS_ALLOWED" = true ] && [ -f "$SCRIPT_PATH" ]; then
    shift
    if [ "$VERBOSE" = true ]; then
        exec "$SCRIPT_PATH" --verbose "$@"
    else
        exec "$SCRIPT_PATH" "$@"
    fi
else
    echo "$(t "cli.error_unknown_command" CMD="$COMMAND")"
    show_help
    exit 1
fi
