#!/usr/bin/env python3
"""Threat actor profiling agent using MITRE ATT&CK STIX data and STIX2 library."""

import json
import sys
import os

try:
    from stix2 import MemoryStore, Filter
    import requests
except ImportError:
    print("Install: pip install stix2 requests")
    sys.exit(1)

ATTACK_STIX_URL = "https://raw.githubusercontent.com/mitre/cti/master/enterprise-attack/enterprise-attack.json"


def load_attack_data(cache_path="/tmp/enterprise-attack.json"):
    """Load MITRE ATT&CK STIX data from cache or download."""
    if os.path.exists(cache_path):
        with open(cache_path, "r") as f:
            data = json.load(f)
    else:
        resp = requests.get(ATTACK_STIX_URL, timeout=60)
        resp.raise_for_status()
        data = resp.json()
        with open(cache_path, "w") as f:
            json.dump(data, f)
    return MemoryStore(stix_data=data["objects"])


def list_threat_groups(src):
    """List all threat actor groups in ATT&CK."""
    groups = src.query([Filter("type", "=", "intrusion-set")])
    result = []
    for g in groups:
        aliases = getattr(g, "aliases", [])
        result.append({
            "id": g.id,
            "name": g.name,
            "aliases": aliases if aliases else [],
            "description": (g.description[:200] + "...") if hasattr(g, "description") and g.description else "",
            "created": str(g.created),
            "modified": str(g.modified),
        })
    return sorted(result, key=lambda x: x["name"])


def get_group_profile(src, group_name):
    """Build a comprehensive profile for a specific threat actor group."""
    groups = src.query([
        Filter("type", "=", "intrusion-set"),
        Filter("name", "=", group_name),
    ])
    if not groups:
        groups = src.query([Filter("type", "=", "intrusion-set")])
        groups = [g for g in groups if group_name.lower() in g.name.lower()
                  or any(group_name.lower() in a.lower() for a in getattr(g, "aliases", []))]
    if not groups:
        return {"error": f"Group '{group_name}' not found"}
    group = groups[0]
    profile = {
        "name": group.name,
        "id": group.id,
        "aliases": getattr(group, "aliases", []),
        "description": getattr(group, "description", ""),
        "created": str(group.created),
        "modified": str(group.modified),
        "external_references": [],
    }
    for ref in getattr(group, "external_references", []):
        if hasattr(ref, "source_name"):
            profile["external_references"].append({
                "source": ref.source_name,
                "url": getattr(ref, "url", ""),
                "external_id": getattr(ref, "external_id", ""),
            })
    relationships = src.query([
        Filter("type", "=", "relationship"),
        Filter("source_ref", "=", group.id),
    ])
    profile["techniques"] = []
    profile["software"] = []
    for rel in relationships:
        target = src.get(rel.target_ref)
        if target:
            if target.type == "attack-pattern":
                technique = {
                    "name": target.name,
                    "technique_id": "",
                    "description": rel.description[:200] if hasattr(rel, "description") and rel.description else "",
                }
                for ref in getattr(target, "external_references", []):
                    if hasattr(ref, "external_id") and ref.external_id.startswith("T"):
                        technique["technique_id"] = ref.external_id
                profile["techniques"].append(technique)
            elif target.type in ("malware", "tool"):
                profile["software"].append({
                    "name": target.name,
                    "type": target.type,
                    "description": (target.description[:200] + "...") if hasattr(target, "description") and target.description else "",
                })
    return profile


def get_group_techniques_by_tactic(src, group_name):
    """Map a group's techniques organized by ATT&CK tactic."""
    profile = get_group_profile(src, group_name)
    if "error" in profile:
        return profile
    tactic_map = {}
    techniques = src.query([Filter("type", "=", "attack-pattern")])
    tech_lookup = {}
    for t in techniques:
        for ref in getattr(t, "external_references", []):
            if hasattr(ref, "external_id") and ref.external_id.startswith("T"):
                tech_lookup[t.name] = {
                    "id": ref.external_id,
                    "tactics": [p["phase_name"] for p in getattr(t, "kill_chain_phases", [])],
                }
    for tech in profile["techniques"]:
        info = tech_lookup.get(tech["name"], {})
        for tactic in info.get("tactics", ["unknown"]):
            tactic_map.setdefault(tactic, []).append({
                "technique": tech["name"],
                "id": info.get("id", tech.get("technique_id", "")),
            })
    return {"group": group_name, "tactics": tactic_map}


def compare_groups(src, group_names):
    """Compare techniques and tools across multiple threat actor groups."""
    profiles = {}
    for name in group_names:
        p = get_group_profile(src, name)
        if "error" not in p:
            profiles[name] = p
    all_techniques = {}
    for name, profile in profiles.items():
        for tech in profile["techniques"]:
            tech_name = tech["name"]
            all_techniques.setdefault(tech_name, set()).add(name)
    shared = {t: list(g) for t, g in all_techniques.items() if len(g) > 1}
    return {
        "groups": list(profiles.keys()),
        "shared_techniques": shared,
        "technique_counts": {n: len(p["techniques"]) for n, p in profiles.items()},
        "software_counts": {n: len(p["software"]) for n, p in profiles.items()},
    }


def print_profile(profile):
    print(f"Threat Actor Profile: {profile['name']}")
    print("=" * 50)
    if profile.get("aliases"):
        print(f"Aliases: {', '.join(profile['aliases'])}")
    print(f"\nDescription:\n{profile.get('description', '')[:500]}")
    print(f"\nTechniques ({len(profile.get('techniques', []))}):")
    for t in profile.get("techniques", [])[:20]:
        print(f"  [{t.get('technique_id', 'N/A'):8s}] {t['name']}")
    print(f"\nSoftware ({len(profile.get('software', []))}):")
    for s in profile.get("software", []):
        print(f"  [{s['type']:7s}] {s['name']}")
    print(f"\nReferences:")
    for r in profile.get("external_references", [])[:5]:
        print(f"  {r['source']}: {r.get('url', r.get('external_id', ''))}")


if __name__ == "__main__":
    group_name = sys.argv[1] if len(sys.argv) > 1 else "APT29"
    print("Loading MITRE ATT&CK data...")
    src = load_attack_data()
    profile = get_group_profile(src, group_name)
    if "error" in profile:
        print(profile["error"])
        print("\nAvailable groups:")
        for g in list_threat_groups(src)[:20]:
            print(f"  {g['name']}: {', '.join(g['aliases'][:3])}")
    else:
        print_profile(profile)
