"""Pinned runtime constants for the APM adapter layer.

Mirrors the Node-side config (src/agent/observability/apm/config.ts) and
the demo (frameworks-py/src/runner/config.py). Keep in lockstep.
"""
from __future__ import annotations

import os
import socket
from datetime import datetime
from typing import Mapping


# --- APM endpoint resolution (same env protocol as Node) ---

APM_ENDPOINTS: dict[str, str] = {
    "ap-beijing": "http://ap-beijing.apm.tencentcs.com:55681",
    "ap-singapore": "http://ap-singapore.apm.tencentcs.com:55681",
}
DEFAULT_REGION = "ap-singapore"


def resolve_apm_endpoint() -> str:
    """Resolve APM endpoint from TENCENTCLOUD_REGION env var."""
    region = os.environ.get("TENCENTCLOUD_REGION", DEFAULT_REGION)
    return APM_ENDPOINTS.get(region, APM_ENDPOINTS[DEFAULT_REGION])


_cached_dev_service_name: str | None = None


def resolve_service_name() -> str:
    """Resolve service_name: {projectId}-{deploymentId}, fallback to dir+datetime."""
    project_id = os.environ.get("PAGES_PROJECT_ID", "")
    deployment_id = os.environ.get("PAGES_DEPLOYMENT_ID", "")
    if project_id and deployment_id:
        return f"{project_id}-{deployment_id}"
    if os.environ.get("OTEL_SERVICE_NAME"):
        return os.environ["OTEL_SERVICE_NAME"]
    # Dev mode: parent process (agent-observability) generates a unified
    # service name via EDGEONE_DEV_SERVICE_NAME so that Node.js and Python
    # runtimes share the same name on APM dual-export.
    if os.environ.get("EDGEONE_DEV_SERVICE_NAME"):
        return os.environ["EDGEONE_DEV_SERVICE_NAME"]
    # Fallback dev mode: project name + datetime (cached per process).
    global _cached_dev_service_name
    if _cached_dev_service_name is None:
        basename = os.path.basename(os.path.dirname(os.path.dirname(os.getcwd()))) or "agent"
        date_str = datetime.now().strftime("%Y%m%d%H%M%S")
        _cached_dev_service_name = f"{basename}-{date_str}"
    return _cached_dev_service_name


# --- Pinned constants (must match Node side exactly) ---

MIN_LLM_CALL_DURATION_MS = 50

METRIC_EXPORT_INTERVAL_MS = 300_000
METRIC_EXPORT_TIMEOUT_MS = 30_000

APM_IDENTITY_LIBRARY_NAME = "langfuse-sdk"
APM_IDENTITY_LIBRARY_VERSION = "4.3.1"


# --- Identity attrs ---

def _local_ip() -> str:
    try:
        with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
            s.connect(("8.8.8.8", 80))
            return s.getsockname()[0]
    except OSError:
        return "127.0.0.1"


def apm_identity_attrs() -> Mapping[str, str]:
    """Identity fields APM expects on recognised LLM services."""
    hostname = socket.gethostname()
    return {
        "instrumentation.library.name": APM_IDENTITY_LIBRARY_NAME,
        "instrumentation.library.version": APM_IDENTITY_LIBRARY_VERSION,
        "host.name": hostname,
        "ip": _local_ip(),
        "service.instance": hostname,
    }
