"""Nova CloudEvents 1.0 envelope + platform.* semantic conventions (REQ-187).

Defines the standard event envelope for all Nova metrics events. Every
emitter (run_manifest, decision_ledger, confidence_signal, checkov_adapter,
hitl_gates, regression_verify) uses `make_event()` to produce a valid
CloudEvents 1.0 envelope. Events are appended to `metrics/events.jsonl`.

D-120: Nova-native minimal tech (no Kafka/OTel SDK — JSONL + SQLite).
D-125: hybrid model — existing file signals stay as files; the collector
reads them and emits normalized CloudEvents. New emitters emit directly.
"""

import datetime
import hashlib
import json
import os
import sys
import uuid

METRICS_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "metrics")
EVENTS_LOG = os.path.join(METRICS_DIR, "events.jsonl")


def _iso8601_now():
    return datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")


def make_event(event_type, run_id, environment, data, contract_id="", source="nova.platform", subject="", actor_type="confidence-gate", actor_id="confidence_signal"):
    """Build a CloudEvents 1.0 envelope with Nova platform.* conventions.

    Args:
        event_type: e.g. "nova.run.completed", "nova.ai.decision.made"
        run_id: the run identifier (e.g. "run-<epoch>")
        environment: dev|qa|prod|dr
        data: the event payload dict
        contract_id: the contract UUID (optional)
        source: the event source (default "nova.platform")
        subject: the event subject (default "<contract_id>/<env>")
        actor_type: the actor type (default "confidence-gate")
        actor_id: the actor id (default "confidence_signal")

    Returns:
        A CloudEvents 1.0 envelope dict.
    """
    if not subject:
        subject = f"{contract_id}/{environment}" if contract_id else environment
    return {
        "specversion": "1.0",
        "id": str(uuid.uuid4()),
        "source": source,
        "type": event_type,
        "time": _iso8601_now(),
        "subject": subject,
        "datacontenttype": "application/json",
        "platform": {
            "tenant_id": "acdl",
            "run_id": run_id,
            "contract_id": contract_id,
            "environment": environment,
            "actor": {"type": actor_type, "id": actor_id},
            "trace_id": run_id,
        },
        "data": data,
    }


def append_event(event, events_log=None):
    """Append a CloudEvents envelope to the JSONL event log.

    Creates the metrics/ directory if it doesn't exist.
    """
    if events_log is None:
        events_log = EVENTS_LOG
    os.makedirs(os.path.dirname(events_log), exist_ok=True)
    with open(events_log, "a", encoding="utf-8") as fh:
        fh.write(json.dumps(event, sort_keys=True, separators=(",", ":")) + "\n")


def emit(event_type, run_id, environment, data, **kwargs):
    """Make an event + append it to the JSONL log. Convenience wrapper."""
    event = make_event(event_type, run_id, environment, data, **kwargs)
    append_event(event)
    return event


if __name__ == "__main__":
    if len(sys.argv) < 4:
        print("usage: event_envelope.py <event_type> <run_id> <environment> [data.json]", file=sys.stderr)
        sys.exit(2)
    _type = sys.argv[1]
    _run_id = sys.argv[2]
    _env = sys.argv[3]
    _data = {}
    if len(sys.argv) >= 5 and os.path.isfile(sys.argv[4]):
        with open(sys.argv[4]) as f:
            _data = json.load(f)
    ev = emit(_type, _run_id, _env, _data)
    print(json.dumps(ev, indent=2))