#!/usr/bin/env python3
"""Threat Intelligence Feed Integration Agent - Ingests STIX/TAXII and open-source TI feeds."""

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

import requests
from taxii2client.v21 import Collection
from stix2 import Indicator, Bundle, parse

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


def ingest_taxii_feed(taxii_url, collection_url, username, password, hours_back=24):
    """Ingest indicators from a TAXII 2.1 server collection."""
    added_after = (datetime.utcnow() - timedelta(hours=hours_back)).strftime(
        "%Y-%m-%dT%H:%M:%S.000Z"
    )
    collection = Collection(collection_url, user=username, password=password)
    response = collection.get_objects(added_after=added_after, type=["indicator"])
    indicators = []
    for obj in response.get("objects", []):
        indicator = parse(obj)
        indicators.append({
            "id": str(indicator.id),
            "pattern": indicator.pattern,
            "valid_from": str(indicator.valid_from),
            "source": "taxii",
        })
    logger.info("Ingested %d indicators from TAXII feed", len(indicators))
    return indicators


def ingest_urlhaus_feed():
    """Ingest recent malicious URLs from Abuse.ch URLhaus."""
    url = "https://urlhaus-api.abuse.ch/v1/urls/recent/limit/100/"
    resp = requests.post(url, timeout=30)
    data = resp.json()
    indicators = []
    for entry in data.get("urls", []):
        indicators.append({
            "type": "url",
            "value": entry["url"],
            "threat": entry.get("threat", "unknown"),
            "status": entry.get("url_status", "unknown"),
            "tags": entry.get("tags", []),
            "source": "urlhaus",
        })
    logger.info("Ingested %d URLs from URLhaus", len(indicators))
    return indicators


def ingest_feodotracker():
    """Ingest C2 IP blocklist from Abuse.ch Feodo Tracker."""
    url = "https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.json"
    resp = requests.get(url, timeout=30)
    indicators = []
    for entry in resp.json():
        indicators.append({
            "type": "ipv4",
            "value": entry["ip_address"],
            "port": entry.get("port"),
            "malware": entry.get("malware", "unknown"),
            "first_seen": entry.get("first_seen"),
            "source": "feodotracker",
        })
    logger.info("Ingested %d C2 IPs from Feodo Tracker", len(indicators))
    return indicators


def normalize_to_stix(indicators):
    """Convert raw indicators to STIX 2.1 Indicator objects."""
    pattern_map = {
        "ipv4": lambda v: f"[ipv4-addr:value = '{v}']",
        "domain": lambda v: f"[domain-name:value = '{v}']",
        "url": lambda v: f"[url:value = '{v}']",
        "sha256": lambda v: f"[file:hashes.'SHA-256' = '{v}']",
    }
    stix_objects = []
    for ioc in indicators:
        ioc_type = ioc.get("type", "url")
        pattern_fn = pattern_map.get(ioc_type, pattern_map["url"])
        stix_ind = Indicator(
            name=f"{ioc_type}: {ioc['value']}",
            pattern=pattern_fn(ioc["value"]),
            pattern_type="stix",
            valid_from=datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
            labels=[ioc.get("source", "unknown")],
        )
        stix_objects.append(stix_ind)
    logger.info("Normalized %d indicators to STIX 2.1", len(stix_objects))
    return stix_objects


def deduplicate(indicators):
    """Deduplicate indicators across feeds by type:value hash."""
    seen = set()
    unique = []
    for ioc in indicators:
        key = hashlib.sha256(f"{ioc.get('type', '')}:{ioc['value']}".encode()).hexdigest()
        if key not in seen:
            seen.add(key)
            unique.append(ioc)
    logger.info("Deduplicated: %d -> %d unique indicators", len(indicators), len(unique))
    return unique


def export_stix_bundle(stix_objects, output_path):
    """Export STIX 2.1 bundle to JSON file."""
    bundle = Bundle(objects=stix_objects)
    with open(output_path, "w") as f:
        f.write(bundle.serialize(pretty=True))
    logger.info("STIX bundle exported to %s (%d indicators)", output_path, len(stix_objects))


def push_to_splunk_ti(splunk_url, session_key, indicators):
    """Push indicators to Splunk ES threat intelligence framework."""
    headers = {"Authorization": f"Splunk {session_key}"}
    pushed = 0
    for ioc in indicators:
        data = {"ip": ioc["value"], "description": f"{ioc.get('source')}: {ioc['value']}"}
        resp = requests.post(
            f"{splunk_url}/services/data/threat_intel/item/ip_intel",
            headers=headers, data=data,
            verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true",  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
            timeout=30,
        )
        if resp.status_code == 201:
            pushed += 1
    logger.info("Pushed %d indicators to Splunk TI", pushed)


def main():
    parser = argparse.ArgumentParser(description="Threat Intelligence Feed Integration Agent")
    parser.add_argument("--taxii-url", help="TAXII 2.1 server URL")
    parser.add_argument("--taxii-collection", help="TAXII collection URL")
    parser.add_argument("--taxii-user", help="TAXII username")
    parser.add_argument("--taxii-pass", help="TAXII password")
    parser.add_argument("--urlhaus", action="store_true", help="Ingest URLhaus feed")
    parser.add_argument("--feodo", action="store_true", help="Ingest Feodo Tracker feed")
    parser.add_argument("--output", default="ti_bundle.json", help="STIX bundle output")
    args = parser.parse_args()

    all_indicators = []

    if args.taxii_url and args.taxii_collection:
        taxii_iocs = ingest_taxii_feed(
            args.taxii_url, args.taxii_collection, args.taxii_user, args.taxii_pass
        )
        all_indicators.extend(taxii_iocs)

    if args.urlhaus:
        all_indicators.extend(ingest_urlhaus_feed())

    if args.feodo:
        all_indicators.extend(ingest_feodotracker())

    unique = deduplicate(all_indicators)
    stix_objects = normalize_to_stix(unique)
    export_stix_bundle(stix_objects, args.output)
    logger.info("Feed integration complete: %d total indicators", len(unique))


if __name__ == "__main__":
    main()
