# Command-trigger audit: extract every module-level  X_RE = re.compile(<literal>)
# from wivexx_api.py via AST (no app import, no side effects), then fire natural
# phrasings at each section's trigger and report misses.
import ast
import re
import sys

SRC = __import__("os").path.join(__import__("os").path.dirname(__import__("os").path.abspath(__file__)), "wivexx_api.py")

FLAGS = {"IGNORECASE": re.IGNORECASE, "I": re.IGNORECASE, "VERBOSE": re.VERBOSE,
         "X": re.VERBOSE, "DOTALL": re.DOTALL, "S": re.DOTALL,
         "MULTILINE": re.MULTILINE, "M": re.MULTILINE, "UNICODE": re.UNICODE}

def flag_val(node):
    if isinstance(node, ast.Attribute):
        return FLAGS.get(node.attr, 0)
    if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
        return flag_val(node.left) | flag_val(node.right)
    return 0

tree = ast.parse(open(SRC, encoding="utf-8").read())
regexes = {}
for node in ast.walk(tree):
    if not isinstance(node, ast.Assign) or len(node.targets) != 1:
        continue
    t = node.targets[0]
    if not (isinstance(t, ast.Name) and t.id.endswith("_RE")):
        continue
    v = node.value
    if not (isinstance(v, ast.Call) and isinstance(v.func, ast.Attribute)
            and v.func.attr == "compile"):
        continue
    if not v.args or not isinstance(v.args[0], ast.Constant):
        continue
    pat = v.args[0].value
    fl = 0
    if len(v.args) > 1:
        fl = flag_val(v.args[1])
    for kw in v.keywords:
        if kw.arg == "flags":
            fl = flag_val(kw.value)
    try:
        regexes[t.id] = re.compile(pat, fl)
    except re.error as e:
        print("!! regex failed to compile:", t.id, e)

print(f"extracted {len(regexes)} trigger regexes\n")

# section -> (trigger regex name, phrasings that MUST match it)
BATTERY = {
    "_CURRENT_TIME_RE": ["what time is it", "what's the time"],
    "_CURRENT_DATE_RE": ["what day is it today", "what's the date"],
    "_TIMER_TRIGGER_RE": ["set a timer for 10 minutes", "start a 5 minute timer",
                          "remind me in 20 minutes to check the oven"],
    "_ACTIVE_TIMER_QUERY_RE": ["how much time is left on my timer",
                               "do i have any timers running"],
    "_VERSION_QUERY_RE": ["what version are you on", "which version are you running"],
    "_LATEST_UPDATE_RE": ["what's new in the latest update"],
    "_CHANGELOG_RE": ["show me the changelog"],
    "_BATTERY_RE": ["battery status", "how much battery do i have left"],
    "_WORK_MODE_ON_RE": ["turn on work mode", "activate work mode", "work mode on"],
    "_WORK_MODE_OFF_RE": ["turn off work mode", "work mode off"],
    "_REMEMBER_RE": ["remember that i park on level 3",
                     "remember this: the wifi password is hunter2"],
    "_FORGET_RE": ["forget what i told you about the gym", "forget my gaming account"],
    "_WHAT_REMEMBER_RE": ["what do you remember about my projects",
                          "what do you know about me"],
    "_ADD_GOAL_RE": ["add a goal to post three reels this week"],
    "_COMPLETE_GOAL_RE": ["complete my first goal"],
    "_GOALS_QUERY_RE": ["list my goals", "what are my goals"],
    "_SOCIAL_REPORT_RE": ["give me my social report", "social media report"],
    "_DISK_ANALYZE_RE": ["what's eating my disk space", "analyze my disk"],
    "_PENDING_QUERY_RE": ["any pending tasks", "do i have any pending tasks"],
    "_SHUTDOWN_RE": ["shut down the pc", "shut down the computer in 20 minutes"],
    "_SHUTDOWN_CANCEL_RE": ["cancel the shutdown"],
    "_JOKE_RE": ["tell me a joke", "tell me another joke"],
    "_NOTE_TRIGGER_RE": ["take a note", "make a note"],
    "_NOTE_RE": ["note that i owe marco 20 bucks"],
    "_YOUTUBE_RE": ["play despacito on youtube", "search youtube for lofi beats"],
    "_VOLUME_RE": ["set volume to 50 percent", "volume up", "turn the volume down a bit"],
    "_WEATHER_TRIGGER_RE": ["what's the weather like today", "is it going to rain tomorrow"],
    "_CLIP_RE": ["summarize my clipboard", "translate the clipboard to spanish"],
    "_WINCTL_GATE_RE": ["move this window to the other monitor",
                        "minimize everything except chrome"],
    "_CAL_CREATE_RE": ["schedule lunch with anna tomorrow at 1pm",
                       "book a meeting with marco on friday at noon"],
    "_CAL_QUERY_RE": ["what's on my calendar this week", "what's on my calendar tomorrow"],
    "_GAMING_MODE_RE": ["turn on gaming mode", "enable performance mode"],
    "_LR_IMPORT_RE": ["import to lightroom", "import the photos to lightroom"],
    "_OSD_RE": ["show the game overlay"],
    "_SPEEDTEST_RE": ["test my internet speed", "run a speed test",
                      "how fast is my internet"],
    "_TRANSCRIBE_RE": ["transcribe this recording"],
    "_OPTIMIZE_RE": ["free up memory", "free up some ram", "optimize my pc"],
    "_PERF_HUD_RE": ["show the performance hud"],
    "_ENROLL_RE": ["enroll my voice"],
    "_SCREEN_LABEL_RE": ["number the screen"],
    "_CLICK_N_RE": ["click 7", "click number seven"],
    "_USAGE_QUERY_RE": ["how many tokens have i used today", "token usage"],
    "_CAPABILITY_QUERY_RE": ["what can you do"],
    "_SELF_CLOSE_RE": ["goodbye wivexx", "close wivexx"],
    "_ADD_APP_RE": ["add app blender"],
    "_SAVE_CONV_RE": ["save this conversation"],
    "_AUDIO_OUTPUT_RE": ["switch output to arctis", "change the audio output to speakers"],
    "_CAPTION_RE": ["caption this video", "make captions for this video"],
    "_DELIVER_RE": ["deliver the photos to my client"],
    "_TRACK_SOCIAL_RE": ["track my.studio on instagram"],
    "_WOL_QUERY_RE": ["wake on lan status"],
    # v1.34: media keys + comparative volume (found by the conversation sim)
    "_MEDIA_KEY_RE": ["pause the music", "next song", "play", "stop the music",
                      "previous track", "skip this song"],
    "_VOLUME_RE": ["make it louder", "a bit quieter", "turn it up", "louder"],
}

missing_re = [k for k in BATTERY if k not in regexes]
if missing_re:
    print("triggers not statically extractable (skipped):", missing_re, "\n")

misses, total = [], 0
for name, phrases in BATTERY.items():
    rx = regexes.get(name)
    if rx is None:
        continue
    for p in phrases:
        total += 1
        q = p.lower().strip(" .,!?")
        if not (rx.search(q) or rx.search(p)):
            misses.append((name, p))

print(f"matched {total - len(misses)}/{total} phrasings")
for name, p in misses:
    print(f"  MISS  {name}: {p!r}")
print("=== RESULT:", "ALL PASS" if not misses else f"{len(misses)} MISSES")
