#!/usr/bin/env python3
"""Malware Incident Response Agent - Triages malware infections and automates containment."""

import json
import hashlib
import logging
import os
import argparse
from datetime import datetime

import requests

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)


def hash_file(file_path):
    """Compute SHA-256 and MD5 hashes of a file."""
    sha256 = hashlib.sha256()
    md5 = hashlib.md5()
    with open(file_path, "rb") as f:
        for chunk in iter(lambda: f.read(8192), b""):
            sha256.update(chunk)
            md5.update(chunk)
    return {"sha256": sha256.hexdigest(), "md5": md5.hexdigest()}


def query_virustotal(file_hash, api_key):
    """Query VirusTotal for file hash reputation."""
    url = f"https://www.virustotal.com/api/v3/files/{file_hash}"
    headers = {"x-apikey": api_key}
    resp = requests.get(url, headers=headers, timeout=30)
    if resp.status_code == 200:
        attrs = resp.json()["data"]["attributes"]
        stats = attrs.get("last_analysis_stats", {})
        result = {
            "hash": file_hash,
            "malicious": stats.get("malicious", 0),
            "undetected": stats.get("undetected", 0),
            "total": sum(stats.values()),
            "popular_threat_name": attrs.get("popular_threat_classification", {}).get("suggested_threat_label", ""),
            "type_description": attrs.get("type_description", ""),
            "first_seen": attrs.get("first_submission_date"),
            "tags": attrs.get("tags", []),
        }
        logger.info("VT: %s - %d/%d detections (%s)",
                     file_hash[:16], result["malicious"], result["total"], result["popular_threat_name"])
        return result
    return {"hash": file_hash, "error": resp.status_code}


def query_malwarebazaar(file_hash):
    """Query MalwareBazaar for sample metadata."""
    url = "https://mb-api.abuse.ch/api/v1/"
    resp = requests.post(url, data={"query": "get_info", "hash": file_hash}, timeout=30)
    result = resp.json()
    if result.get("query_status") == "ok":
        sample = result["data"][0]
        return {
            "hash": file_hash,
            "family": sample.get("signature", "unknown"),
            "file_type": sample.get("file_type", "unknown"),
            "delivery_method": sample.get("delivery_method", "unknown"),
            "tags": sample.get("tags", []),
            "intelligence": sample.get("intelligence", {}),
        }
    return {"hash": file_hash, "status": "not_found"}


def query_threatfox_iocs(malware_family):
    """Search ThreatFox for IOCs associated with a malware family."""
    url = "https://threatfox-api.abuse.ch/api/v1/"
    data = {"query": "taginfo", "tag": malware_family, "limit": 50}
    resp = requests.post(url, json=data, timeout=30)
    result = resp.json()
    iocs = []
    if result.get("query_status") == "ok":
        for entry in result.get("data", []):
            iocs.append({
                "ioc": entry.get("ioc"),
                "ioc_type": entry.get("ioc_type"),
                "threat_type": entry.get("threat_type"),
                "malware": entry.get("malware_printable"),
                "confidence": entry.get("confidence_level"),
            })
    logger.info("ThreatFox: %d IOCs for family '%s'", len(iocs), malware_family)
    return iocs


def isolate_endpoint_crowdstrike(api_base, token, device_id):
    """Isolate an infected endpoint via CrowdStrike Falcon API."""
    headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
    resp = requests.post(
        f"{api_base}/devices/entities/devices-actions/v2?action_name=contain",
        headers=headers, json={"ids": [device_id]}, timeout=30,
    )
    if resp.status_code == 202:
        logger.info("Endpoint %s isolated via CrowdStrike", device_id)
        return True
    logger.error("Isolation failed for %s: %d", device_id, resp.status_code)
    return False


def search_enterprise_iocs(splunk_url, session_key, iocs):
    """Search Splunk for IOC matches across the enterprise."""
    ioc_values = [i.get("ioc", "") for i in iocs if i.get("ioc")]
    if not ioc_values:
        return []
    search_terms = " OR ".join([f'"{v}"' for v in ioc_values[:20]])
    query = f'search index=* ({search_terms}) | stats count by host, sourcetype | sort - count'
    resp = requests.post(
        f"{splunk_url}/services/search/jobs",
        headers={"Authorization": f"Splunk {session_key}"},
        data={"search": query, "output_mode": "json"},
        verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30,  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
    )
    return resp.json() if resp.status_code == 201 else []


def generate_malware_ir_report(incident_id, hashes, vt_results, bazaar_results, family_iocs, containment):
    """Generate a malware incident response report."""
    report = {
        "incident_id": incident_id,
        "timestamp": datetime.utcnow().isoformat(),
        "sample_hashes": hashes,
        "virustotal": vt_results,
        "malwarebazaar": bazaar_results,
        "malware_family": bazaar_results.get("family", vt_results.get("popular_threat_name", "Unknown")),
        "related_iocs": family_iocs[:20],
        "containment_actions": containment,
    }
    family = report["malware_family"]
    detections = vt_results.get("malicious", 0)
    print(f"MALWARE IR REPORT - {incident_id}")
    print(f"Family: {family} | VT Detections: {detections} | Related IOCs: {len(family_iocs)}")
    return report


def main():
    parser = argparse.ArgumentParser(description="Malware Incident Response Agent")
    parser.add_argument("--incident-id", required=True, help="Incident ID")
    parser.add_argument("--sample", help="Path to malware sample file")
    parser.add_argument("--hash", help="SHA-256 hash of malware sample")
    parser.add_argument("--vt-key", help="VirusTotal API key")
    parser.add_argument("--cs-token", help="CrowdStrike API token")
    parser.add_argument("--device-id", help="CrowdStrike device ID to isolate")
    parser.add_argument("--output", default="malware_ir_report.json")
    args = parser.parse_args()

    hashes = {}
    if args.sample:
        hashes = hash_file(args.sample)
    elif args.hash:
        hashes = {"sha256": args.hash}

    file_hash = hashes.get("sha256", "")
    vt_results = query_virustotal(file_hash, args.vt_key) if args.vt_key and file_hash else {}
    bazaar_results = query_malwarebazaar(file_hash) if file_hash else {}

    family = bazaar_results.get("family", vt_results.get("popular_threat_name", ""))
    family_iocs = query_threatfox_iocs(family) if family and family != "unknown" else []

    containment = []
    if args.cs_token and args.device_id:
        if isolate_endpoint_crowdstrike("https://api.crowdstrike.com", args.cs_token, args.device_id):
            containment.append(f"Isolated {args.device_id}")

    report = generate_malware_ir_report(
        args.incident_id, hashes, vt_results, bazaar_results, family_iocs, containment
    )
    with open(args.output, "w") as f:
        json.dump(report, f, indent=2)
    logger.info("Report saved to %s", args.output)


if __name__ == "__main__":
    main()
