import json
import os
import time
from datetime import datetime
import win32evtlog  # from pywin32
import xml.etree.ElementTree as ET

# ---------------------------------------------------------
# CONFIGURATION
# ---------------------------------------------------------
# File to monitor (opened + executed)
TARGET_PATH = r"c:\temp\projectVoiceSignature\trump.py".lower()

COUNTER_FILE = "trump_activity_counts.json"
LOG_FILE = "trump_activity_log.txt"

SYSMON_CHANNEL = "Microsoft-Windows-Sysmon/Operational"

# ---------------------------------------------------------
# PERSISTENT STATE
# ---------------------------------------------------------
def load_state():
    if not os.path.exists(COUNTER_FILE):
        return {"open_count": 0, "exec_count": 0, "last_record_id": 0}
    try:
        with open(COUNTER_FILE, "r") as f:
            return json.load(f)
    except:
        return {"open_count": 0, "exec_count": 0, "last_record_id": 0}

def save_state(state):
    with open(COUNTER_FILE, "w") as f:
        json.dump(state, f, indent=4)

def log_event(message):
    with open(LOG_FILE, "a") as f:
        f.write(f"{datetime.now().isoformat()} - {message}\n")

# ---------------------------------------------------------
# SYSMON EVENT PARSING
# ---------------------------------------------------------
def parse_sysmon_event_xml(xml_str):
    """
    Returns: (event_id, record_id, data_dict)
    data_dict: {field_name: value}
    """
    root = ET.fromstring(xml_str)

    ns = {
        "e": "http://schemas.microsoft.com/win/2004/08/events/event"
    }

    system = root.find("e:System", ns)
    event_id = int(system.find("e:EventID", ns).text)
    record_id = int(system.find("e:EventRecordID", ns).text)

    data_dict = {}
    eventdata = root.find("e:EventData", ns)
    if eventdata is not None:
        for d in eventdata.findall("e:Data", ns):
            name = d.get("Name")
            value = d.text or ""
            data_dict[name] = value

    return event_id, record_id, data_dict

# ---------------------------------------------------------
# MAIN LOOP
# ---------------------------------------------------------
def main():
    state = load_state()
    open_count = state.get("open_count", 0)
    exec_count = state.get("exec_count", 0)
    last_record_id = state.get("last_record_id", 0)

    print("Monitoring Sysmon for:")
    print(f"  File path: {TARGET_PATH}")
    print("Events:")
    print("  - Event ID 11: File open (FileCreate)")
    print("  - Event ID 1 : Process execution (ProcessCreate)")
    print("Press CTRL+C to stop.\n")

    query = "*[System[(EventID=1 or EventID=11)]]"

    # Open a query handle to the Sysmon log
    hquery = win32evtlog.EvtQuery(
        SYSMON_CHANNEL,
        win32evtlog.EvtQueryChannelPath,
        query
    )

    try:
        while True:
            events = win32evtlog.EvtNext(hquery, 16, 0, 0)
            if not events:
                time.sleep(1)
                continue

            for ev in events:
                xml = win32evtlog.EvtRender(
                    ev,
                    win32evtlog.EvtRenderEventXml
                )
                event_id, record_id, data = parse_sysmon_event_xml(xml)

                # Skip already processed events (for restarts)
                if record_id <= last_record_id:
                    continue

                last_record_id = record_id

                # Normalize relevant fields
                image = (data.get("Image", "") or "").lower()
                command_line = (data.get("CommandLine", "") or "").lower()
                target_filename = (data.get("TargetFilename", "") or "").lower()

                # ---- FILE OPEN (Event ID 11) ----
                if event_id == 11:
                    if target_filename == TARGET_PATH:
                        open_count += 1
                        state = {
                            "open_count": open_count,
                            "exec_count": exec_count,
                            "last_record_id": last_record_id,
                        }
                        save_state(state)

                        msg = f"OPEN: {target_filename} | Count={open_count}"
                        log_event(msg)
                        print(f"[OPEN] {TARGET_PATH} opened. Total opens: {open_count}")

                # ---- EXECUTION (Event ID 1) ----
                elif event_id == 1:
                    # Match either exact image path or command line containing it
                    if image == TARGET_PATH or TARGET_PATH in command_line:
                        exec_count += 1
                        state = {
                            "open_count": open_count,
                            "exec_count": exec_count,
                            "last_record_id": last_record_id,
                        }
                        save_state(state)

                        msg = (
                            f"EXEC: {image} | CMD={command_line} | "
                            f"Count={exec_count}"
                        )
                        log_event(msg)
                        print(f"[EXEC] {TARGET_PATH} executed. Total execs: {exec_count}")

    except KeyboardInterrupt:
        print("\nStopped monitoring.")
        state = {
            "open_count": open_count,
            "exec_count": exec_count,
            "last_record_id": last_record_id,
        }
        save_state(state)

if __name__ == "__main__":
    main()
