#!/usr/bin/env python3
"""Agent for analyzing security logs with Splunk using splunk-sdk."""

import os
import json
import time
import argparse
from datetime import datetime

import splunklib.client as client
import splunklib.results as results


def connect_splunk(host, port, username, password):
    """Establish connection to Splunk instance."""
    service = client.connect(
        host=host,
        port=port,
        username=username,
        password=password,
        autologin=True,
    )
    return service


def run_search(service, query, earliest="-24h", latest="now"):
    """Execute a Splunk search and return parsed results."""
    kwargs_search = {
        "earliest_time": earliest,
        "latest_time": latest,
        "search_mode": "normal",
        "exec_mode": "blocking",
    }
    job = service.jobs.create(f"search {query}", **kwargs_search)
    reader = results.JSONResultsReader(job.results(output_mode="json"))
    rows = [row for row in reader if isinstance(row, dict)]
    job.cancel()
    return rows


def detect_brute_force(service, threshold=10, earliest="-24h"):
    """Detect brute force attacks via failed logon events (EventCode 4625)."""
    query = (
        'index=windows sourcetype="WinEventLog:Security" EventCode=4625 '
        f"| stats count as failed_attempts, dc(src_ip) as unique_sources, "
        f"values(src_ip) as source_ips by TargetUserName "
        f"| where failed_attempts > {threshold} "
        f"| sort -failed_attempts"
    )
    return run_search(service, query, earliest=earliest)


def detect_lateral_movement(service, earliest="-24h"):
    """Detect lateral movement via Type 3 network logons to multiple hosts."""
    query = (
        'index=windows sourcetype="WinEventLog:Security" EventCode=4624 '
        "Logon_Type=3 "
        "| stats dc(ComputerName) as unique_targets, values(ComputerName) as targets "
        "by TargetUserName, src_ip "
        "| where unique_targets > 3 "
        "| sort -unique_targets"
    )
    return run_search(service, query, earliest=earliest)


def detect_suspicious_powershell(service, earliest="-24h"):
    """Detect encoded or download-cradle PowerShell execution via Sysmon."""
    query = (
        'index=sysmon EventCode=1 Image="*\\\\powershell.exe" '
        '(CommandLine="*-enc*" OR CommandLine="*-encodedcommand*" '
        'OR CommandLine="*downloadstring*" OR CommandLine="*iex*") '
        "| table _time, host, User, ParentImage, CommandLine "
        "| sort _time"
    )
    return run_search(service, query, earliest=earliest)


def detect_lsass_access(service, earliest="-24h"):
    """Detect credential dumping via LSASS process access (Sysmon Event 10)."""
    query = (
        'index=sysmon EventCode=10 TargetImage="*\\\\lsass.exe" '
        "GrantedAccess=0x1010 "
        "| table _time, host, SourceImage, SourceUser, GrantedAccess"
    )
    return run_search(service, query, earliest=earliest)


def build_incident_timeline(service, hosts, users, earliest="-24h", latest="now"):
    """Build a unified incident timeline across multiple log sources."""
    host_filter = " OR ".join(f'host="{h}"' for h in hosts)
    user_filter = " OR ".join(f'user="{u}"' for u in users)
    query = (
        f"index=windows OR index=sysmon OR index=proxy OR index=firewall "
        f"({host_filter} OR {user_filter}) "
        '| eval event_summary=case('
        '    sourcetype=="WinEventLog:Security" AND EventCode==4624, '
        '    "Logon: ".TargetUserName." from ".src_ip, '
        '    sourcetype=="WinEventLog:Security" AND EventCode==4625, '
        '    "Failed logon: ".TargetUserName, '
        '    EventCode==1, "Process: ".Image." by ".User, '
        '    1==1, sourcetype.": ".EventCode) '
        "| table _time, sourcetype, host, event_summary "
        "| sort _time"
    )
    return run_search(service, query, earliest=earliest, latest=latest)


def generate_report(findings):
    """Format investigation findings into a structured report."""
    report = {
        "report_type": "SPLUNK INVESTIGATION REPORT",
        "generated_at": datetime.utcnow().isoformat() + "Z",
        "findings": findings,
    }
    return json.dumps(report, indent=2, default=str)


def main():
    parser = argparse.ArgumentParser(description="Splunk Security Log Analysis Agent")
    parser.add_argument("--host", default=os.getenv("SPLUNK_HOST", "localhost"))
    parser.add_argument("--port", type=int, default=int(os.getenv("SPLUNK_PORT", "8089")))
    parser.add_argument("--username", default=os.getenv("SPLUNK_USERNAME", "admin"))
    parser.add_argument("--password", default=os.getenv("SPLUNK_PASSWORD", ""))
    parser.add_argument("--earliest", default="-24h", help="Search earliest time")
    parser.add_argument("--action", choices=[
        "brute_force", "lateral_movement", "powershell",
        "lsass_access", "timeline", "full_investigation"
    ], default="full_investigation")
    parser.add_argument("--hosts", nargs="*", default=[], help="Target hosts for timeline")
    parser.add_argument("--users", nargs="*", default=[], help="Target users for timeline")
    parser.add_argument("--threshold", type=int, default=10)
    args = parser.parse_args()

    service = connect_splunk(args.host, args.port, args.username, args.password)
    findings = {}

    if args.action in ("brute_force", "full_investigation"):
        findings["brute_force"] = detect_brute_force(service, args.threshold, args.earliest)
        print(f"[+] Brute force: {len(findings['brute_force'])} accounts targeted")

    if args.action in ("lateral_movement", "full_investigation"):
        findings["lateral_movement"] = detect_lateral_movement(service, args.earliest)
        print(f"[+] Lateral movement: {len(findings['lateral_movement'])} suspicious paths")

    if args.action in ("powershell", "full_investigation"):
        findings["suspicious_powershell"] = detect_suspicious_powershell(service, args.earliest)
        print(f"[+] Suspicious PowerShell: {len(findings['suspicious_powershell'])} events")

    if args.action in ("lsass_access", "full_investigation"):
        findings["lsass_access"] = detect_lsass_access(service, args.earliest)
        print(f"[+] LSASS access: {len(findings['lsass_access'])} events")

    if args.action == "timeline" and args.hosts:
        findings["timeline"] = build_incident_timeline(
            service, args.hosts, args.users, args.earliest
        )
        print(f"[+] Timeline: {len(findings['timeline'])} events")

    print(generate_report(findings))


if __name__ == "__main__":
    main()
