from __future__ import annotations

import json
import os
import re
import sys
from collections.abc import Mapping
from datetime import datetime, timedelta, timezone
from typing import Any

_PUBLISHER: Any | None = None
_TOPIC_PATH = ""
_BRT = timezone(timedelta(hours=-3))
_ISO_EVENT_TIMESTAMP_RE = re.compile(
    r"^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d{1,9}))?Z$"
)
_PUBSUB_EVENT_TIMESTAMP_RE = re.compile(r"^(\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}),(\d{1,9})$")
_EXCLUDED_PAYLOAD_KEYS = {"original_message_id"}


def _config() -> tuple[str, str] | None:
    project_id = (os.getenv("GCP_PROJECT_ID", "") or "").strip()
    topic = (os.getenv("AGENT_PUBSUB_TOPIC", "") or "").strip()
    if not project_id or not topic:
        return None
    return project_id, topic


def _topic_path(publisher: Any, project_id: str, topic: str) -> str:
    if topic.startswith("projects/") and "/topics/" in topic:
        return topic
    return str(publisher.topic_path(project_id, topic))


def _publisher() -> tuple[Any, str] | None:
    global _PUBLISHER, _TOPIC_PATH

    config = _config()
    if config is None:
        return None

    if _PUBLISHER is not None and _TOPIC_PATH:
        return _PUBLISHER, _TOPIC_PATH

    project_id, topic = config
    try:
        from google.cloud import pubsub_v1

        _PUBLISHER = pubsub_v1.PublisherClient()
        _TOPIC_PATH = _topic_path(_PUBLISHER, project_id, topic)
        return _PUBLISHER, _TOPIC_PATH
    except Exception as exc:
        print(f"STRUCTURED_EVENT_PUBSUB_DISABLED | error={type(exc).__name__}: {exc}", file=sys.stderr)
        return None


def _log_publish_error(future: Any) -> None:
    try:
        future.result()
    except Exception as exc:
        print(f"STRUCTURED_EVENT_PUBSUB_PUBLISH_FAIL | error={type(exc).__name__}: {exc}", file=sys.stderr)


def _format_pubsub_timestamp(value: Any) -> str:
    raw = str(value or "").strip()
    if not raw:
        return ""

    pubsub_match = _PUBSUB_EVENT_TIMESTAMP_RE.match(raw)
    if pubsub_match is not None:
        return f"{pubsub_match.group(1)},{pubsub_match.group(2).ljust(9, '0')[:9]}"

    iso_match = _ISO_EVENT_TIMESTAMP_RE.match(raw)
    if iso_match is None:
        return raw

    dt = datetime.strptime(iso_match.group(1), "%Y-%m-%dT%H:%M:%S")
    local_dt = dt.replace(tzinfo=timezone.utc).astimezone(_BRT)
    fractional_ns = (iso_match.group(2) or "").ljust(9, "0")[:9]
    return f"{local_dt:%d/%m/%Y %H:%M:%S},{fractional_ns}"


def _pubsub_payload(event: Mapping[str, Any]) -> dict[str, Any]:
    payload = {key: value for key, value in event.items() if str(key) not in _EXCLUDED_PAYLOAD_KEYS}

    if "session_id" in payload:
        if payload.get("sessionId") in (None, ""):
            payload["sessionId"] = payload.get("session_id")
        del payload["session_id"]

    if "dat_hora_fim" in payload:
        if payload.get("dat_hora_termino") in (None, ""):
            payload["dat_hora_termino"] = payload.get("dat_hora_fim")
        del payload["dat_hora_fim"]

    if "dat_hora_inicio" in payload:
        payload["dat_hora_inicio"] = _format_pubsub_timestamp(payload.get("dat_hora_inicio"))
    if "dat_hora_termino" in payload:
        payload["dat_hora_termino"] = _format_pubsub_timestamp(payload.get("dat_hora_termino"))

    return payload


def publish_structured_event(event: Mapping[str, Any]) -> None:
    publisher_config = _publisher()
    if publisher_config is None:
        return

    publisher, topic_path = publisher_config
    try:
        payload = _pubsub_payload(event)
        payload_json = json.dumps(payload, ensure_ascii=False).encode("utf-8")
        future = publisher.publish(
            topic_path,
            payload_json,
            tipo_evento=str(payload.get("tipo_evento") or ""),
            dat_hora_inicio=str(payload.get("dat_hora_inicio") or ""),
            dat_hora_termino=str(payload.get("dat_hora_termino") or ""),
            sessionId=str(payload.get("sessionId") or ""),
            callid=str(payload.get("callid") or ""),
            nome_agente=str(payload.get("nome_agente") or ""),
            cod_ani=str(payload.get("cod_ani") or ""),
            http_cod_status=str(payload.get("http_cod_status") or ""),
            http_cod_desc=str(payload.get("http_cod_desc") or ""),
        )
        future.add_done_callback(_log_publish_error)
    except Exception as exc:
        print(f"STRUCTURED_EVENT_PUBSUB_PUBLISH_FAIL | error={type(exc).__name__}: {exc}", file=sys.stderr)
