"""obol tray — system tray alert responder.

Shows session status via tray icon color. Left-click opens a panel with
rich alert cards — each detection is explained in plain English with
action buttons to allow, explain, or override right there.

Watches ~/.obol/sessions/ for changes.

Requires PyQt6 (already present on KDE systems).
Fallback: pip install obol-sdk[tray]

Usage:
    obol tray              Start tray indicator
    obol tray --no-poll    Don't auto-refresh
"""
import json
import os
import subprocess
import shutil
import sys
import time
import webbrowser

SESSIONS_DIR = os.path.expanduser("~/.obol/sessions")
LOCKDOWN_PATH = os.path.expanduser("~/.obol/lockdown")
CONFIG_PATH = os.path.expanduser("~/.obol/config.json")
DASHBOARD_URL = "https://obol.grayowlresearch.com/dashboard"
POLL_INTERVAL = 3000  # ms


def _check_deps():
    try:
        from PyQt6.QtWidgets import QApplication  # noqa: F401
        return []
    except ImportError:
        return ["PyQt6"]


def _find_latest_session():
    if not os.path.isdir(SESSIONS_DIR):
        return None
    best = None
    best_mtime = 0
    for fname in os.listdir(SESSIONS_DIR):
        if not fname.endswith(".json"):
            continue
        fpath = os.path.join(SESSIONS_DIR, fname)
        try:
            mtime = os.path.getmtime(fpath)
        except OSError:
            continue
        if mtime > best_mtime:
            best = fpath
            best_mtime = mtime
    return best


def _load_session_ux(path):
    try:
        with open(path) as f:
            data = json.load(f)
        return data.get("ux_stats", {})
    except Exception:
        return {}


def _is_locked():
    return os.path.exists(LOCKDOWN_PATH)


def _get_config():
    try:
        with open(CONFIG_PATH) as f:
            return json.load(f)
    except Exception:
        return {}


# ── Message catalog accessors ─────────────────────────────────────────
# Import from messages.py if available, else use fallbacks

def _get_msg_funcs():
    """Return (get_flag_title, get_flag_explanation, get_user_severity)."""
    try:
        from obol.hooks.messages import (
            get_flag_title, get_flag_explanation, get_user_severity,
        )
        return get_flag_title, get_flag_explanation, get_user_severity
    except ImportError:
        def _title(f):
            return f.replace("_", " ").title()
        def _expl(f):
            return f"Detection flag '{f}' was triggered."
        def _sev(f):
            return "INFO"
        return _title, _expl, _sev


def _run_obol_cmd(args_list):
    """Run an obol CLI command in the background."""
    terminals = [
        ["konsole", "-e"],
        ["gnome-terminal", "--"],
        ["xfce4-terminal", "-e"],
        ["xterm", "-e"],
    ]
    cmd_str = " ".join(args_list) + "; echo; read -p 'Press Enter...'"
    for term_cmd in terminals:
        if shutil.which(term_cmd[0]):
            try:
                subprocess.Popen(
                    term_cmd + ["bash", "-c", cmd_str],
                    start_new_session=True,
                )
                return True
            except Exception:
                continue
    return False


# ── Severity config ───────────────────────────────────────────────────

SEV_COLORS = {
    "CRITICAL": "#f38ba8",  # Red
    "WARNING":  "#fab387",  # Peach/orange
    "INFO":     "#f9e2af",  # Yellow
    "FYI":      "#a6adc8",  # Gray
}

SEV_ICONS = {
    "CRITICAL": "\u26d4",   # ⛔
    "WARNING":  "\u26a0\ufe0f",  # ⚠️
    "INFO":     "\u2139\ufe0f",  # ℹ️
    "FYI":      "\u2022",   # •
}

SEV_BG = {
    "CRITICAL": "#2a1f2e",
    "WARNING":  "#2a251f",
    "INFO":     "#252520",
    "FYI":      "#1e1e2e",
}


def _build_tray_app(poll=True):
    from PyQt6.QtWidgets import (
        QApplication, QSystemTrayIcon, QMenu, QWidget,
        QVBoxLayout, QHBoxLayout, QLabel, QPushButton,
        QFrame, QScrollArea, QSizePolicy, QGraphicsOpacityEffect,
    )
    from PyQt6.QtGui import (
        QIcon, QPixmap, QPainter, QColor, QFont, QCursor,
        QPen, QPainterPath, QLinearGradient,
    )
    from PyQt6.QtCore import (
        Qt, QTimer, QSize, QRectF, QPropertyAnimation, QEasingCurve,
    )

    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(False)
    get_title, get_explanation, get_severity = _get_msg_funcs()

    # ── Icon generation ──────────────────────────────────────────
    def make_icon(color_hex, alert=False, size=64):
        """Create tray icon — coin shape with optional alert pip."""
        pm = QPixmap(size, size)
        pm.fill(QColor(0, 0, 0, 0))
        p = QPainter(pm)
        p.setRenderHint(QPainter.RenderHint.Antialiasing)

        # Outer ring
        p.setPen(QPen(QColor(color_hex), 3))
        p.setBrush(QColor(0, 0, 0, 0))
        p.drawEllipse(6, 6, size - 12, size - 12)

        # Inner fill (subtle)
        inner = QColor(color_hex)
        inner.setAlpha(50)
        p.setPen(Qt.PenStyle.NoPen)
        p.setBrush(inner)
        p.drawEllipse(10, 10, size - 20, size - 20)

        # Center dot
        p.setBrush(QColor(color_hex))
        p.drawEllipse(size // 2 - 4, size // 2 - 4, 8, 8)

        # Alert pip (top-right red dot)
        if alert:
            p.setBrush(QColor("#f38ba8"))
            p.setPen(QPen(QColor("#1e1e2e"), 2))
            p.drawEllipse(size - 18, 2, 16, 16)

        p.end()
        return QIcon(pm)

    icons = {
        "green": make_icon("#a6e3a1"),
        "green_alert": make_icon("#a6e3a1", alert=True),
        "yellow": make_icon("#f9e2af"),
        "yellow_alert": make_icon("#f9e2af", alert=True),
        "red": make_icon("#f38ba8"),
        "red_alert": make_icon("#f38ba8", alert=True),
        "gray": make_icon("#6c7086"),
    }

    # ── State ────────────────────────────────────────────────────
    state = {
        "ux": {},
        "path": None,
        "mtime": 0,
        "seen_count": 0,   # Detections we've already shown
        "new_alerts": False,
    }

    def refresh():
        path = _find_latest_session()
        if path:
            try:
                mtime = os.path.getmtime(path)
            except OSError:
                mtime = 0
            if path != state["path"] or mtime != state["mtime"]:
                old_deferred = len(state["ux"].get("deferred", []))
                state["path"] = path
                state["mtime"] = mtime
                state["ux"] = _load_session_ux(path)
                new_deferred = len(state["ux"].get("deferred", []))
                if new_deferred > old_deferred:
                    state["new_alerts"] = True

    def get_status():
        if _is_locked():
            return "red"
        ux = state["ux"]
        if not ux or not ux.get("total"):
            return "gray"
        deferred = ux.get("deferred", [])
        if not deferred:
            return "green"
        for entry in deferred:
            flag = entry[0] if isinstance(entry, (list, tuple)) else ""
            sev = get_severity(flag)
            if sev in ("CRITICAL", "WARNING"):
                return "red"
        return "yellow"

    def get_icon_key():
        base = get_status()
        if state["new_alerts"] and base != "gray":
            return base + "_alert"
        return base

    # ── Stylesheet ───────────────────────────────────────────────
    PANEL_STYLE = """
    QWidget#panel {
        background: #1e1e2e;
        border: 1px solid #313244;
        border-radius: 12px;
    }
    QScrollArea {
        background: transparent;
        border: none;
    }
    QScrollBar:vertical {
        background: #1e1e2e;
        width: 6px;
        margin: 4px 2px;
        border-radius: 3px;
    }
    QScrollBar::handle:vertical {
        background: #45475a;
        border-radius: 3px;
        min-height: 20px;
    }
    QScrollBar::handle:vertical:hover { background: #585b70; }
    QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0; }
    QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; }
    QLabel { color: #cdd6f4; }
    QPushButton {
        border: 1px solid #45475a;
        border-radius: 6px;
        padding: 4px 10px;
        font-size: 11px;
        color: #cdd6f4;
        background: #313244;
    }
    QPushButton:hover { background: #45475a; border-color: #585b70; }
    QPushButton#btn-allow { color: #a6e3a1; border-color: #a6e3a1; }
    QPushButton#btn-allow:hover { background: #1a2e1a; }
    QPushButton#btn-explain { color: #89b4fa; border-color: #89b4fa; }
    QPushButton#btn-explain:hover { background: #1a1e2e; }
    QPushButton#btn-override { color: #fab387; border-color: #fab387; }
    QPushButton#btn-override:hover { background: #2e251a; }
    QPushButton#btn-dashboard {
        background: #89b4fa; color: #1e1e2e; border: none;
        font-weight: bold; padding: 8px 16px; border-radius: 8px;
    }
    QPushButton#btn-dashboard:hover { background: #b4d0fb; }
    QFrame#card {
        background: #181825;
        border: 1px solid #313244;
        border-radius: 10px;
    }
    QFrame#separator { background: #313244; max-height: 1px; }
    """

    # ── Panel ────────────────────────────────────────────────────
    panel = QWidget()
    panel.setWindowFlags(
        Qt.WindowType.Popup
        | Qt.WindowType.FramelessWindowHint
        | Qt.WindowType.NoDropShadowWindowHint
    )
    panel.setFixedWidth(420)
    panel.setMaximumHeight(600)
    panel.setObjectName("panel")
    panel.setStyleSheet(PANEL_STYLE)

    root_layout = QVBoxLayout(panel)
    root_layout.setContentsMargins(16, 14, 16, 14)
    root_layout.setSpacing(0)

    # ── Header ───────────────────────────────────────────────────
    header = QHBoxLayout()
    header.setSpacing(8)

    # Status dot
    status_dot = QLabel()
    status_dot.setFixedSize(10, 10)

    logo_label = QLabel("OBOL")
    logo_label.setStyleSheet(
        "font-size: 13px; font-weight: 800; letter-spacing: 3px; "
        "color: #cdd6f4;"
    )

    mode_badge = QLabel("")
    mode_badge.setStyleSheet(
        "font-size: 9px; font-weight: bold; color: #1e1e2e; "
        "background: #a6adc8; border-radius: 3px; padding: 2px 6px;"
    )

    stat_label = QLabel("")
    stat_label.setStyleSheet("font-size: 11px; color: #6c7086;")

    header.addWidget(status_dot)
    header.addWidget(logo_label)
    header.addSpacing(6)
    header.addWidget(mode_badge)
    header.addStretch()
    header.addWidget(stat_label)
    root_layout.addLayout(header)
    root_layout.addSpacing(10)

    # ── Scroll area for alert cards ──────────────────────────────
    scroll = QScrollArea()
    scroll.setWidgetResizable(True)
    scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
    scroll.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
    scroll.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)

    card_container = QWidget()
    card_container.setStyleSheet("background: transparent;")
    card_layout = QVBoxLayout(card_container)
    card_layout.setContentsMargins(0, 0, 4, 0)
    card_layout.setSpacing(8)

    scroll.setWidget(card_container)
    root_layout.addWidget(scroll)

    # ── Empty state ──────────────────────────────────────────────
    empty_label = QLabel("")
    empty_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
    empty_label.setStyleSheet("color: #6c7086; font-size: 12px; padding: 20px;")
    empty_label.setWordWrap(True)

    # ── Footer ───────────────────────────────────────────────────
    root_layout.addSpacing(10)
    footer = QHBoxLayout()
    footer.setSpacing(8)

    btn_dashboard = QPushButton("Open Dashboard")
    btn_dashboard.setObjectName("btn-dashboard")
    btn_dashboard.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))

    btn_review = QPushButton("Terminal Review")
    btn_review.setStyleSheet(
        "font-size: 11px; color: #89b4fa; background: transparent; "
        "border: 1px solid #45475a; border-radius: 8px; padding: 8px 16px;"
    )
    btn_review.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))

    footer.addWidget(btn_dashboard)
    footer.addWidget(btn_review)
    root_layout.addLayout(footer)

    # ── Lockdown banner ──────────────────────────────────────────
    lockdown_banner = QFrame()
    lockdown_banner.setStyleSheet(
        "background: #2a1520; border: 1px solid #f38ba8; border-radius: 8px;"
    )
    lockdown_layout = QVBoxLayout(lockdown_banner)
    lockdown_layout.setContentsMargins(12, 10, 12, 10)
    lockdown_title = QLabel("\u26d4  AGENT LOCKED DOWN")
    lockdown_title.setStyleSheet(
        "font-size: 14px; font-weight: bold; color: #f38ba8;"
    )
    lockdown_title.setAlignment(Qt.AlignmentFlag.AlignCenter)
    lockdown_hint = QLabel("Run: obol unlock")
    lockdown_hint.setStyleSheet("font-size: 11px; color: #f5c2e7;")
    lockdown_hint.setAlignment(Qt.AlignmentFlag.AlignCenter)
    lockdown_layout.addWidget(lockdown_title)
    lockdown_layout.addWidget(lockdown_hint)
    lockdown_banner.setVisible(False)

    # Insert lockdown banner before scroll area
    root_layout.insertWidget(2, lockdown_banner)

    # ── Build an alert card ──────────────────────────────────────
    def make_alert_card(flag, tool, target, ts):
        """Create a rich alert card widget for a single detection."""
        sev = get_severity(flag)
        title = get_title(flag)
        explanation = get_explanation(flag)
        sev_color = SEV_COLORS.get(sev, "#a6adc8")
        sev_bg = SEV_BG.get(sev, "#1e1e2e")
        sev_icon = SEV_ICONS.get(sev, "\u2022")

        card = QFrame()
        card.setObjectName("card")
        card.setStyleSheet(f"""
            QFrame#card {{
                background: {sev_bg};
                border: 1px solid {sev_color}40;
                border-left: 3px solid {sev_color};
                border-radius: 10px;
            }}
        """)

        clayout = QVBoxLayout(card)
        clayout.setContentsMargins(12, 10, 12, 10)
        clayout.setSpacing(4)

        # Row 1: severity icon + title + time
        row1 = QHBoxLayout()
        row1.setSpacing(6)

        sev_badge = QLabel(sev)
        sev_badge.setStyleSheet(
            f"font-size: 9px; font-weight: bold; color: {sev_color}; "
            f"background: {sev_color}20; border-radius: 3px; padding: 1px 5px;"
        )
        title_lbl = QLabel(title)
        title_lbl.setStyleSheet(
            f"font-size: 13px; font-weight: bold; color: {sev_color};"
        )
        ts_str = time.strftime("%H:%M:%S", time.localtime(ts)) if ts else ""
        time_lbl = QLabel(ts_str)
        time_lbl.setStyleSheet("font-size: 10px; color: #6c7086;")

        row1.addWidget(sev_badge)
        row1.addWidget(title_lbl)
        row1.addStretch()
        row1.addWidget(time_lbl)
        clayout.addLayout(row1)

        # Row 2: explanation
        expl_lbl = QLabel(explanation)
        expl_lbl.setWordWrap(True)
        expl_lbl.setStyleSheet("font-size: 11px; color: #bac2de; padding: 2px 0;")
        clayout.addWidget(expl_lbl)

        # Row 3: command preview (monospace)
        if target:
            cmd_preview = (target or "")[:120]
            cmd_lbl = QLabel(cmd_preview)
            cmd_lbl.setStyleSheet(
                "font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace; "
                "font-size: 10px; color: #9399b2; background: #11111b; "
                "border-radius: 4px; padding: 4px 6px;"
            )
            cmd_lbl.setWordWrap(True)
            cmd_lbl.setTextInteractionFlags(
                Qt.TextInteractionFlag.TextSelectableByMouse
            )
            clayout.addWidget(cmd_lbl)

        # Row 4: tool label
        tool_lbl = QLabel(f"Tool: {tool}" if tool else "")
        tool_lbl.setStyleSheet("font-size: 10px; color: #6c7086;")
        clayout.addWidget(tool_lbl)

        # Row 5: action buttons
        btn_row = QHBoxLayout()
        btn_row.setSpacing(6)
        btn_row.addStretch()

        btn_allow = QPushButton("Allow")
        btn_allow.setObjectName("btn-allow")
        btn_allow.setFixedHeight(26)
        btn_allow.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
        btn_allow.setToolTip(f"Add '{flag}' to local allowlist")

        btn_explain = QPushButton("Explain")
        btn_explain.setObjectName("btn-explain")
        btn_explain.setFixedHeight(26)
        btn_explain.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
        btn_explain.setToolTip(f"Open terminal with: obol explain {flag}")

        btn_row.addWidget(btn_allow)
        btn_row.addWidget(btn_explain)

        # Wire button actions
        def on_allow():
            try:
                from obol.hooks.allowlist import add_rule
                rule_id = add_rule(flag, tool=tool)
                btn_allow.setText("\u2713 Allowed")
                btn_allow.setEnabled(False)
                btn_allow.setStyleSheet(
                    "color: #a6e3a1; background: #1a2e1a; border-color: #a6e3a1; "
                    "border-radius: 6px; padding: 4px 10px; font-size: 11px;"
                )
            except Exception as e:
                btn_allow.setText("Error")

        def on_explain():
            _run_obol_cmd(["obol", "explain", flag])
            panel.hide()

        btn_allow.clicked.connect(on_allow)
        btn_explain.clicked.connect(on_explain)

        clayout.addLayout(btn_row)
        return card

    # ── Update panel ─────────────────────────────────────────────
    def update_panel():
        ux = state["ux"]
        total = ux.get("total", 0)
        clean = ux.get("clean", 0)
        flagged = ux.get("flagged", 0)
        deferred = ux.get("deferred", [])
        locked = _is_locked()

        config = _get_config()
        mode = config.get("enforcement_mode", "audit").upper()
        mode_colors = {
            "AUDIT": "#a6adc8",
            "ALERT": "#f9e2af",
            "ENFORCE": "#f38ba8",
        }
        mc = mode_colors.get(mode, "#a6adc8")
        mode_badge.setText(mode)
        mode_badge.setStyleSheet(
            f"font-size: 9px; font-weight: bold; color: #1e1e2e; "
            f"background: {mc}; border-radius: 3px; padding: 2px 6px;"
        )

        # Status dot
        status = get_status()
        dot_colors = {
            "green": "#a6e3a1", "yellow": "#f9e2af",
            "red": "#f38ba8", "gray": "#6c7086",
        }
        dc = dot_colors.get(status, "#6c7086")
        status_dot.setStyleSheet(
            f"background: {dc}; border-radius: 5px; border: none;"
        )

        # Stats
        if total:
            stat_label.setText(f"{clean}\u2713  {flagged}\u26a0  {total} total")
        else:
            stat_label.setText("No session")

        # Lockdown
        lockdown_banner.setVisible(locked)

        # Clear old cards
        while card_layout.count():
            item = card_layout.takeAt(0)
            w = item.widget()
            if w:
                w.deleteLater()

        if not deferred:
            if locked:
                empty_label.setText(
                    "Agent is locked down.\n"
                    "Run 'obol unlock' in terminal to restore."
                )
            elif total:
                empty_label.setText(
                    "\u2713  All clear\n"
                    f"{total} events, no detections"
                )
            else:
                empty_label.setText(
                    "No active session.\n"
                    "Detections will appear here when your agent is running."
                )
            card_layout.addWidget(empty_label)
            empty_label.setVisible(True)
        else:
            empty_label.setVisible(False)
            # Show most recent first, up to 20
            shown = list(reversed(deferred[-20:]))
            for entry in shown:
                if not isinstance(entry, (list, tuple)) or len(entry) < 1:
                    continue
                flag = entry[0]
                tool = entry[1] if len(entry) > 1 else ""
                target = entry[2] if len(entry) > 2 else ""
                ts = entry[3] if len(entry) > 3 else 0
                card = make_alert_card(flag, tool, target, ts)
                card_layout.addWidget(card)

        card_layout.addStretch()
        state["new_alerts"] = False
        panel.adjustSize()

    # ── Button handlers ──────────────────────────────────────────
    def on_dashboard():
        config = _get_config()
        url = config.get("api_url", "").replace("/v1", "")
        if not url:
            url = DASHBOARD_URL.rsplit("/dashboard", 1)[0]
        webbrowser.open(url + "/dashboard")
        panel.hide()

    def on_review():
        _run_obol_cmd(["obol", "review"])
        panel.hide()

    btn_dashboard.clicked.connect(on_dashboard)
    btn_review.clicked.connect(on_review)

    # ── Tray icon ────────────────────────────────────────────────
    tray = QSystemTrayIcon()
    tray.setIcon(icons.get(get_icon_key(), icons["gray"]))
    tray.setToolTip("Obol — Agent Security Monitor")

    menu = QMenu()
    quit_action = menu.addAction("Quit Obol Tray")
    quit_action.triggered.connect(app.quit)
    tray.setContextMenu(menu)

    def on_activated(reason):
        if reason == QSystemTrayIcon.ActivationReason.Trigger:
            if panel.isVisible():
                panel.hide()
            else:
                refresh()
                update_panel()
                # Position near tray icon
                geo = tray.geometry()
                if geo.isValid() and geo.x() > 0:
                    x = geo.x() - panel.width() // 2 + geo.width() // 2
                    y = geo.y() - panel.height() - 8
                else:
                    cursor = QCursor.pos()
                    x = cursor.x() - panel.width() // 2
                    y = cursor.y() - panel.height() - 20
                screen = app.primaryScreen().geometry()
                x = max(8, min(x, screen.width() - panel.width() - 8))
                y = max(8, min(y, screen.height() - panel.height() - 8))
                panel.move(x, y)
                panel.show()
                panel.raise_()

    tray.activated.connect(on_activated)
    tray.show()

    # ── Desktop notification for new critical/warning alerts ─────
    last_notified = {"count": 0}

    def maybe_notify():
        deferred = state["ux"].get("deferred", [])
        if len(deferred) <= last_notified["count"]:
            return
        # Check new entries for CRITICAL/WARNING
        new_entries = deferred[last_notified["count"]:]
        last_notified["count"] = len(deferred)
        for entry in new_entries:
            if not isinstance(entry, (list, tuple)) or len(entry) < 1:
                continue
            flag = entry[0]
            sev = get_severity(flag)
            if sev in ("CRITICAL", "WARNING"):
                title = get_title(flag)
                tray.showMessage(
                    f"Obol: {title}",
                    get_explanation(flag),
                    QSystemTrayIcon.MessageIcon.Warning,
                    5000,
                )
                break  # One notification per poll cycle

    # ── Polling ──────────────────────────────────────────────────
    if poll:
        timer = QTimer()

        def tick():
            old_key = get_icon_key()
            refresh()
            new_key = get_icon_key()
            if old_key != new_key:
                tray.setIcon(icons.get(new_key, icons["gray"]))
            if panel.isVisible():
                update_panel()
            maybe_notify()

        timer.timeout.connect(tick)
        timer.start(POLL_INTERVAL)

    # Initial
    refresh()
    update_panel()
    tray.setIcon(icons.get(get_icon_key(), icons["gray"]))

    print("Obol tray indicator started.", file=sys.stderr)
    sys.exit(app.exec())


def cmd_tray(args):
    missing = _check_deps()
    if missing:
        print(f"Missing: {', '.join(missing)}")
        print("Install with: pip install PyQt6")
        print("(Already present on KDE systems)")
        return

    poll = not getattr(args, "no_poll", False)
    try:
        _build_tray_app(poll=poll)
    except KeyboardInterrupt:
        pass
    except Exception as e:
        print(f"Tray error: {e}", file=sys.stderr)
        import traceback
        traceback.print_exc(file=sys.stderr)
        sys.exit(1)


def setup_parser(subparsers):
    parser = subparsers.add_parser(
        "tray", help="System tray alert responder")
    parser.add_argument(
        "--no-poll", action="store_true",
        help="Don't auto-refresh")
    parser.set_defaults(func=cmd_tray)
