#!/usr/bin/env python3
"""Insider threat behavior detection agent using UEBA indicators.

Analyzes user activity logs to detect anomalous behaviors: off-hours access,
mass file downloads, unusual data access patterns, and privilege abuse.
"""

import argparse
import json
from collections import defaultdict
from datetime import datetime

RISK_INDICATORS = {
    "off_hours_access": {"weight": 15, "desc": "Activity outside business hours"},
    "mass_download": {"weight": 25, "desc": "Bulk file download/copy"},
    "privilege_escalation": {"weight": 30, "desc": "Unauthorized privilege use"},
    "unusual_destination": {"weight": 20, "desc": "Data sent to unusual destination"},
    "resignation_correlated": {"weight": 35, "desc": "Activity correlated with resignation"},
    "usb_mass_copy": {"weight": 30, "desc": "Mass copy to removable media"},
    "cloud_upload": {"weight": 20, "desc": "Large upload to personal cloud"},
    "email_to_personal": {"weight": 15, "desc": "Forwarding to personal email"},
}

BUSINESS_HOURS = (8, 18)
PERSONAL_DOMAINS = {"gmail.com", "yahoo.com", "hotmail.com", "outlook.com",
                    "protonmail.com", "icloud.com", "aol.com"}
CLOUD_STORAGE = {"dropbox.com", "drive.google.com", "onedrive.live.com",
                 "box.com", "mega.nz", "wetransfer.com"}


def parse_activity_log(filepath):
    events = []
    with open(filepath, "r", encoding="utf-8", errors="replace") as f:
        for line in f:
            line = line.strip()
            if not line:
                continue
            try:
                evt = json.loads(line)
                events.append(evt)
            except json.JSONDecodeError:
                parts = line.split(",")
                if len(parts) >= 4:
                    events.append({
                        "timestamp": parts[0], "user": parts[1],
                        "action": parts[2], "detail": ",".join(parts[3:]),
                    })
    return events


def detect_off_hours(events):
    findings = []
    for evt in events:
        ts = evt.get("timestamp", "")
        try:
            dt = datetime.fromisoformat(ts.replace("Z", "+00:00"))
            hour = dt.hour
            if hour < BUSINESS_HOURS[0] or hour >= BUSINESS_HOURS[1]:
                findings.append({
                    "indicator": "off_hours_access",
                    "user": evt.get("user", ""),
                    "timestamp": ts,
                    "hour": hour,
                    "action": evt.get("action", ""),
                })
        except (ValueError, TypeError):
            continue
    return findings


def detect_mass_download(events, threshold=50):
    user_downloads = defaultdict(list)
    for evt in events:
        action = evt.get("action", "").lower()
        if any(kw in action for kw in ("download", "copy", "export", "fileaccessed")):
            user_downloads[evt.get("user", "")].append(evt)

    findings = []
    for user, downloads in user_downloads.items():
        if len(downloads) >= threshold:
            findings.append({
                "indicator": "mass_download",
                "user": user,
                "file_count": len(downloads),
                "time_range": f"{downloads[0].get('timestamp', '')} - {downloads[-1].get('timestamp', '')}",
                "severity": "HIGH" if len(downloads) > 100 else "MEDIUM",
            })
    return findings


def detect_data_exfil_destinations(events):
    findings = []
    for evt in events:
        detail = evt.get("detail", "").lower()
        dest = evt.get("destination", "").lower()
        target = detail + " " + dest

        for domain in PERSONAL_DOMAINS:
            if domain in target:
                findings.append({
                    "indicator": "email_to_personal",
                    "user": evt.get("user", ""),
                    "destination": domain,
                    "timestamp": evt.get("timestamp", ""),
                })
        for cloud in CLOUD_STORAGE:
            if cloud in target:
                findings.append({
                    "indicator": "cloud_upload",
                    "user": evt.get("user", ""),
                    "destination": cloud,
                    "timestamp": evt.get("timestamp", ""),
                })
        if any(kw in target for kw in ("usb", "removable", "external drive", "e:")):
            findings.append({
                "indicator": "usb_mass_copy",
                "user": evt.get("user", ""),
                "timestamp": evt.get("timestamp", ""),
            })
    return findings


def calculate_risk_score(user_findings):
    score = 0
    indicators = set()
    for f in user_findings:
        ind = f.get("indicator", "")
        if ind in RISK_INDICATORS:
            score += RISK_INDICATORS[ind]["weight"]
            indicators.add(ind)
    risk = "CRITICAL" if score >= 80 else "HIGH" if score >= 50 else \
           "MEDIUM" if score >= 25 else "LOW"
    return {"score": min(score, 100), "risk_level": risk, "indicators": list(indicators)}


def main():
    parser = argparse.ArgumentParser(description="Insider Threat Behavior Detector")
    parser.add_argument("--activity-log", required=True, help="User activity log (JSON lines or CSV)")
    parser.add_argument("--download-threshold", type=int, default=50)
    args = parser.parse_args()

    events = parse_activity_log(args.activity_log)
    all_findings = []
    all_findings.extend(detect_off_hours(events))
    all_findings.extend(detect_mass_download(events, args.download_threshold))
    all_findings.extend(detect_data_exfil_destinations(events))

    user_findings = defaultdict(list)
    for f in all_findings:
        user_findings[f.get("user", "unknown")].append(f)

    user_risks = {}
    for user, findings in user_findings.items():
        user_risks[user] = calculate_risk_score(findings)
        user_risks[user]["finding_count"] = len(findings)

    results = {
        "timestamp": datetime.utcnow().isoformat() + "Z",
        "total_events": len(events),
        "total_findings": len(all_findings),
        "user_risk_scores": user_risks,
        "findings": all_findings,
    }
    print(json.dumps(results, indent=2))


if __name__ == "__main__":
    main()
