#!/usr/bin/env python3
"""Threat intelligence collection agent using MISP/PyMISP.

Connects to MISP instances to collect, filter, and export threat intelligence
including events, attributes, and feeds via the PyMISP REST API client.
"""

import json
import os
import datetime

try:
    from pymisp import PyMISP
    HAS_PYMISP = True
except ImportError:
    HAS_PYMISP = False


def init_misp(url=None, key=None):
    """Initialize PyMISP client."""
    url = url or os.environ.get("MISP_URL", "https://misp.example.org")
    key = key or os.environ.get("MISP_API_KEY", "")
    if not HAS_PYMISP:
        return None
    return PyMISP(url, key, ssl=True)


def search_events(misp, tags=None, date_from=None, published=True, limit=50):
    """Search MISP events by tags and date."""
    if not misp:
        return {"error": "PyMISP not available"}
    kwargs = {"limit": limit, "published": published, "pythonify": True}
    if tags:
        kwargs["tags"] = tags
    if date_from:
        kwargs["date_from"] = date_from
    try:
        events = misp.search("events", **kwargs)
        return [
            {
                "id": e.id,
                "uuid": e.uuid,
                "info": e.info,
                "date": str(e.date),
                "threat_level": {1: "High", 2: "Medium", 3: "Low", 4: "Undefined"}.get(e.threat_level_id, "?"),
                "analysis": {0: "Initial", 1: "Ongoing", 2: "Complete"}.get(e.analysis, "?"),
                "attribute_count": e.attribute_count,
                "org": e.Orgc.name if hasattr(e, "Orgc") and e.Orgc else "",
                "tags": [t.name for t in (e.tags or [])],
            }
            for e in events
        ]
    except Exception as e:
        return {"error": str(e)}


def extract_attributes(misp, event_id, attr_type=None):
    """Extract attributes from a MISP event."""
    if not misp:
        return {"error": "PyMISP not available"}
    try:
        kwargs = {"eventid": event_id, "pythonify": True}
        if attr_type:
            kwargs["type_attribute"] = attr_type
        attrs = misp.search("attributes", **kwargs)
        return [
            {
                "type": a.type,
                "value": a.value,
                "category": a.category,
                "to_ids": a.to_ids,
                "comment": a.comment or "",
                "timestamp": str(datetime.datetime.fromtimestamp(int(a.timestamp))),
            }
            for a in attrs
        ]
    except Exception as e:
        return {"error": str(e)}


def collect_iocs_by_type(misp, ioc_types, date_from=None, limit=500):
    """Collect IOCs filtered by attribute type."""
    if not misp:
        return {"error": "PyMISP not available"}
    results = {}
    for ioc_type in ioc_types:
        try:
            kwargs = {"type_attribute": ioc_type, "to_ids": True, "pythonify": True, "limit": limit}
            if date_from:
                kwargs["date_from"] = date_from
            attrs = misp.search("attributes", **kwargs)
            results[ioc_type] = [
                {"value": a.value, "event_id": a.event_id, "comment": a.comment or ""}
                for a in attrs
            ]
        except Exception as e:
            results[ioc_type] = {"error": str(e)}
    return results


def list_feeds(misp):
    """List configured MISP feeds."""
    if not misp:
        return {"error": "PyMISP not available"}
    try:
        feeds = misp.feeds()
        return [
            {
                "id": f["Feed"]["id"],
                "name": f["Feed"]["name"],
                "provider": f["Feed"]["provider"],
                "url": f["Feed"]["url"],
                "enabled": f["Feed"]["enabled"],
                "source_format": f["Feed"]["source_format"],
            }
            for f in feeds
        ]
    except Exception as e:
        return {"error": str(e)}


def export_stix2(misp, event_id):
    """Export MISP event as STIX 2.1 bundle."""
    if not misp:
        return {"error": "PyMISP not available"}
    try:
        stix_data = misp.get_stix_event(event_id)
        return stix_data
    except Exception as e:
        return {"error": str(e)}


COMMON_IOC_TYPES = [
    "ip-dst", "ip-src", "domain", "hostname", "url",
    "md5", "sha1", "sha256", "email-src", "filename",
]


if __name__ == "__main__":
    print("=" * 60)
    print("Threat Intelligence Collection with MISP")
    print("PyMISP REST client, event search, attribute extraction, feeds")
    print("=" * 60)
    print("  PyMISP available: {}".format(HAS_PYMISP))

    misp = init_misp() if HAS_PYMISP else None

    if not misp:
        print("\n[DEMO] No MISP connection. Showing IOC types and feed structure.")
        print("\n--- Common IOC Types ---")
        for t in COMMON_IOC_TYPES:
            print("  - {}".format(t))
        print("\n--- Usage ---")
        print("  Set MISP_URL and MISP_API_KEY environment variables")
        print("  python agent.py")
    else:
        print("\n[*] Searching recent events...")
        events = search_events(misp, date_from="7d")
        if isinstance(events, list):
            print("  Found {} events".format(len(events)))
            for e in events[:5]:
                print("    [{}] {} ({} attrs)".format(e["id"], e["info"][:60], e["attribute_count"]))
        else:
            print("  Error: {}".format(events))

        feeds = list_feeds(misp)
        if isinstance(feeds, list):
            print("\n--- Feeds ({}) ---".format(len(feeds)))
            for f in feeds[:10]:
                status = "enabled" if f["enabled"] else "disabled"
                print("  [{}] {} ({})".format(f["id"], f["name"], status))

    print("\n" + json.dumps({"pymisp_available": HAS_PYMISP}, indent=2))
