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")


TYPES_TO_OPENCTI = {
    "account": "User-Account", "domain": "Domain-Name", "email": "Email-Addr",
    "file-md5": "StixFile", "file-sha1": "StixFile", "file-sha256": "StixFile", "file": "StixFile",
    "host": "X-OpenCTI-Hostname", "ip": "IPv4-Addr", "ipv6": "IPv6-Addr",
    "registry key": "Windows-Registry-Key", "url": "Url",
}
OBSERVABLE_TYPE_TO_STIX_PATTERN = {
    "IPv4-Addr": "[ipv4-addr:value = '{{indicator}}']",
    "IPv6-Addr": "[ipv6-addr:value = '{{indicator}}']",
    "Domain-Name": "[domain-name:value = '{{indicator}}']",
    "Url": "[url:value = '{{indicator}}']",
    "Email-Addr": "[email-addr:value = '{{indicator}}']",
    "StixFile": "[file:hashes.'SHA-256' = '{{indicator}}']",
    "Process": "[process:pid = '{{indicator}}']",
    "User-Account": "[user-account:user_id = '{{indicator}}']",
    "Windows-Registry-Key": "[windows-registry-key:key = '{{indicator}}']",
}


def build_stix_pattern(indicator, observable_type):
    if observable_type not in OBSERVABLE_TYPE_TO_STIX_PATTERN:
        fail(f"Invalid observable type: {observable_type}")
    return OBSERVABLE_TYPE_TO_STIX_PATTERN[observable_type].replace("{{indicator}}", indicator)


name = I.get("name")
indicator = I.get("indicator")
main_observable_type = TYPES_TO_OPENCTI.get(str(I.get("main_observable_type", "")).lower(), I.get("main_observable_type"))
description = I.get("description")
valid_from = I.get("valid_from")
valid_until = I.get("valid_until")
created_by = I.get("created_by")
label_id = I.get("label_id")
marking_id = I.get("marking_id")
external_references_id = I.get("external_references_id")

pattern = build_stix_pattern(indicator, main_observable_type)

try:
    result = client().indicator.create(
        name=name,
        description=description,
        pattern=pattern,
        pattern_type="stix",
        x_opencti_main_observable_type=main_observable_type,
        indicator_types=as_list(I.get("indicator_types")),
        confidence=as_int(I.get("confidence"), 50),
        x_opencti_score=as_int(I.get("score"), 50),
        valid_from=valid_from,
        valid_until=valid_until,
        createdBy=created_by,
        objectLabel=label_id,
        objectMarking=marking_id,
        externalReferences=external_references_id,
        x_opencti_create_observables=as_bool(I.get("create_observables")),
    )
except Exception as e:
    fail("Can't create indicator in OpenCTI.", detail=str(e))

out({"id": result.get("id")})
