import win32evtlog
import json
import requests
import os
import sys
import logging
from datetime import datetime

# File to store the last processed record number
LAST_PROCESSED_FILE = 'last_processed_record.txt'

# Splunk HEC configuration
SPLUNK_HEC_TOKEN = 'xxxxxxxxxxx'
SPLUNK_HEC_URL = 'https://172.31.1.245:8088/services/collector/event'

# Configuration
server = 'localhost'
log_name = 'Data Security Essentials'
source_names = ['Superna Data Security Essentials BOT Service', 'Superna Data Security Policy Engine']
trigger_severities = ['MAJOR', 'CRITICAL']  # Adjust as needed

def setup_logging():
    script_directory = os.path.dirname(os.path.abspath(__file__))
    log_file_path = os.path.join(script_directory, "splunk-dse.log")

    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s - %(levelname)s - %(message)s',
                        handlers=[
                            logging.FileHandler(log_file_path, mode='w'),
                            logging.StreamHandler(sys.stdout)
                        ])
    logging.info(f"Script run on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    logging.info(f"Logging to file: {log_file_path}")

def get_last_processed_record():
    if os.path.exists(LAST_PROCESSED_FILE):
        try:
            with open(LAST_PROCESSED_FILE, 'r') as f:
                lines = f.readlines()
                if len(lines) >= 2:
                    last_record = int(lines[0].strip())
                    last_time_and_event_id = lines[1].strip()
                    logging.info(f"Loaded last processed record: {last_record}, {last_time_and_event_id}")
                    return last_record, last_time_and_event_id
        except Exception as e:
            logging.error(f"Error reading {LAST_PROCESSED_FILE}: {e}")
    logging.info(f"No last processed record file found. Starting fresh.")
    return 0, None

def save_last_processed_record(record_number, event_time, event_id):
    try:
        with open(LAST_PROCESSED_FILE, 'w') as f:
            f.write(f"{record_number}\n")
            f.write(f"{event_time} | EventID: {event_id}\n")
        logging.info(f"Saved last processed record: {record_number}, {event_time}, EventID: {event_id}")
    except Exception as e:
        logging.error(f"Error saving {LAST_PROCESSED_FILE}: {e}")

def send_to_splunk(event_json):
    """Send a structured payload to Splunk via HEC."""
    splunk_event = {
        "sourcetype": "supernaZT",
        "event": {
            "user": event_json.get("user"),
            "state": event_json.get("state"),
            "userName": event_json.get("userName"),
            "protocol": event_json.get("protocol"),
            "eventSource": event_json.get("eventSource"),
            "numFiles": event_json.get("numFiles"),
            "nes": event_json.get("nes"),
            "detected": event_json.get("detected"),
            "clientIPs": event_json.get("clientIPs"),
            "shares": event_json.get("shares"),
            "files": event_json.get("files"),
            # Add more fields as needed
        }
    }

    headers = {
        'Authorization': f'Splunk {SPLUNK_HEC_TOKEN}',
        'Content-Type': 'application/json'
    }

    try:
        response = requests.post(SPLUNK_HEC_URL, headers=headers, data=json.dumps(splunk_event), verify=False)
        response.raise_for_status()
        logging.info("Successfully sent event to Splunk.")
    except requests.RequestException as e:
        logging.error(f"Failed to send event to Splunk: {e}")

def collect_windows_event_log(server, log_name, source_names):
    logging.info(f"Collecting Windows Event Logs from {log_name} on server {server}...")
    h = win32evtlog.OpenEventLog(server, log_name)
    flags = win32evtlog.EVENTLOG_BACKWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ

    last_processed_record, last_time_and_event_id = get_last_processed_record()

    latest_record = last_processed_record
    latest_event_time = None
    latest_event_id = None

    try:
        while True:
            events = win32evtlog.ReadEventLog(h, flags, 0)
            if not events:
                break

            for event in events:
                record_number = event.RecordNumber
                event_time = event.TimeGenerated.Format()
                event_id = event.EventID & 0xFFFF

                if record_number <= last_processed_record:
                    continue
                if event.SourceName not in source_names:
                    continue

                logging.info(f"Processing Event - RecordNumber: {record_number}, EventID: {event_id}, TimeGenerated: {event_time}, Source: {event.SourceName}")

                try:
                    if event.Data:
                        data_content = event.Data.decode('utf-8', errors='replace')
                        logging.debug(f"Raw JSON Payload: {data_content}")

                        try:
                            event_json = json.loads(data_content)
                            logging.debug(f"Parsed JSON: {json.dumps(event_json, indent=2)}")

                            severity = event_json.get('severity')
                            if severity not in trigger_severities:
                                logging.info(f"Event severity '{severity}' does not match filter. Skipping.")
                                continue

                            send_to_splunk(event_json)

                        except json.JSONDecodeError as e:
                            logging.error(f"JSON parsing failed: {e}")
                except Exception as e:
                    logging.warning(f"Event processing failed: {e}")

                latest_record = max(latest_record, record_number)
                latest_event_time = event_time
                latest_event_id = event_id

    finally:
        win32evtlog.CloseEventLog(h)

    if latest_event_time and latest_event_id:
        save_last_processed_record(latest_record, latest_event_time, latest_event_id)

def main():
    setup_logging()
    collect_windows_event_log(server, log_name, source_names)

if __name__ == "__main__":
    main()
