import json, os, sys

S = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
I = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))


def out(value):
    print(json.dumps(value, default=str))


def fail(message, **extra):
    payload = {"error": message}
    payload.update(extra)
    print(json.dumps(payload, default=str))
    sys.exit(1)


def as_bool(v):
    return v if isinstance(v, bool) else str(v).lower() in ("1", "true", "yes")


def as_int(v, default=None):
    try:
        return int(v)
    except (TypeError, ValueError):
        return default


def as_list(v):
    if isinstance(v, list):
        return v
    if v in (None, ""):
        return []
    return [x.strip() for x in str(v).split(",") if x.strip()]


try:
    from pycti import OpenCTIApiClient
except ImportError as e:
    fail("The 'pycti' Python library is required for the OpenCTI integration. "
         "Install it on the execution host (engine): pip install pycti", detail=str(e))


def client():
    base = str(S.get("base_url", "")).strip().rstrip("/")
    api_key = S.get("api_key") or (S.get("credentials") or {}).get("password")
    return OpenCTIApiClient(base, api_key, ssl_verify=not as_bool(S.get("insecure")), log_level="error")


def get_incidents(client, search="", created_by=None, creator=None, created_after=None,
                  created_before=None, incident_types=None, label=None, limit=500,
                  last_run_id=None, get_all=False):
    filters = {"mode": "and", "filters": [], "filterGroups": []}
    if label:
        filters["filters"].append({"key": "objectLabel", "values": [label], "operator": "eq", "mode": "or"})
    if created_by:
        filters["filters"].append({"key": "createdBy", "values": [created_by], "operator": "eq", "mode": "or"})
    if creator:
        filters["filters"].append({"key": "creator_id", "values": [creator], "operator": "eq"})
    if incident_types:
        filters["filters"].append({"key": "incident_types", "values": incident_types, "operator": "eq", "mode": "or"})
    if created_after:
        filters["filters"].append({"key": "created_at", "values": [created_after], "operator": "gt"})
    if created_before:
        filters["filters"].append({"key": "created_at", "values": [created_before], "operator": "lt"})
    return client.incident.list(
        after=last_run_id, first=limit, withPagination=True, getAll=get_all, filters=filters, search=search
    )


search = I.get("search", "")
created_by = I.get("created_by")
creator = I.get("creator")
created_after = I.get("created_after")
created_before = I.get("created_before")
incident_types = as_list(I.get("incident_types"))
label = I.get("label_id")
limit = as_int(I.get("limit", 500), 500)
last_run_id = I.get("last_run_id")
get_all = as_bool(I.get("all_results", "false"))

try:
    raw = get_incidents(
        client(),
        search=search,
        created_by=created_by,
        creator=creator,
        created_after=created_after,
        created_before=created_before,
        incident_types=incident_types,
        label=label,
        limit=limit,
        last_run_id=last_run_id,
        get_all=get_all,
    )
except Exception as e:
    fail("Can't list incidents from OpenCTI.", detail=str(e))

last_run = None if get_all else raw.get("pagination", {}).get("endCursor")
incidents_list = raw if get_all else raw.get("entities", [])

normalized = []
for incident in incidents_list:
    normalized.append({
        "id": incident.get("id"),
        "name": incident.get("name"),
        "description": incident.get("description"),
        "source": incident.get("source"),
        "confidence": incident.get("confidence"),
        "severity": incident.get("severity"),
        "objective": incident.get("objective"),
        "createdBy": (incident.get("createdBy") or {}).get("name") or "",
        "creators": [c.get("name") for c in incident.get("creators", [])],
        "labels": [l.get("value") for l in incident.get("objectLabel", [])],
        "incidentTypes": incident.get("incident_types"),
        "created": incident.get("created"),
        "updatedAt": incident.get("updated_at"),
    })

out({"entities": normalized, "pagination": {"endCursor": last_run}})
