"""reddit_capi.py — send a Reddit CAPI SignUp conversion event.

Faithful port of the BE team's spec (reddit-capi-signup-python.md), which is itself
a port of app/Services/RedditCapiService.php. Only deviations from that doc:
  - uses httpx (already a dependency) instead of requests
  - `from __future__ import annotations` so `str | None` hints are safe on Python 3.9
Everything about the wire payload is identical.
"""

from __future__ import annotations

import hashlib
import time

import httpx

ENDPOINT = "https://ads-api.reddit.com/api/v3/pixels/{pixel_id}/conversion_events"
TRACKING_TYPE_SIGNUP = "SignUp"
ACTION_SOURCE_APP = "APP"
ACTION_SOURCE_WEBSITE = "WEBSITE"
HTTP_TIMEOUT_SECONDS = 10

_BASE36_DIGITS = "0123456789abcdefghijklmnopqrstuvwxyz"


# --------------------------------------------------------------------------- #
# Helpers
# --------------------------------------------------------------------------- #
def _now_ms() -> int:
    """Current unix time in milliseconds (matches PHP round(microtime(true)*1000))."""
    return int(round(time.time() * 1000))


def _to_base36(number: int) -> str:
    """Lowercase base-36 of a non-negative int (matches PHP base_convert(n, 10, 36))."""
    if number == 0:
        return "0"
    out = ""
    while number > 0:
        number, rem = divmod(number, 36)
        out = _BASE36_DIGITS[rem] + out
    return out


def generate_event_id(external_id: str, event_type: str) -> str:
    """
    Time-based, unique event id.

    Format: "{external_id}-{event_type}-{base36 ms timestamp}"
    For SignUp, event_type is "1". Example: "u12345-1-ms5zraf6".
    """
    return f"{external_id}-{event_type}-{_to_base36(_now_ms())}"


def generate_conversion_id(external_id: str, tracking_type: str) -> str:
    """
    Deduplication id: SHA-256 of "{seed}-{tracking_type}-{base36 ms}".
    seed falls back to 'anon' when external_id is empty.
    """
    seed = external_id if external_id else "anon"
    raw = f"{seed}-{tracking_type}-{_to_base36(_now_ms())}"
    return hashlib.sha256(raw.encode("utf-8")).hexdigest()


def hash_email(email: str) -> str:
    """Reddit requires SHA-256 of the normalized (trimmed + lowercased) email."""
    return hashlib.sha256(email.strip().lower().encode("utf-8")).hexdigest()


def _build_user(data: dict) -> dict:
    """Assemble the `user` object, including only non-empty fields."""
    user = {}
    if data.get("email"):
        user["email"] = str(data["email"])
    if data.get("external_id"):
        user["external_id"] = str(data["external_id"])
    if data.get("client_ip"):
        user["ip_address"] = str(data["client_ip"])
    if data.get("user_agent"):
        user["user_agent"] = str(data["user_agent"])

    ad_id = data.get("advertising_id")
    device = str(data.get("device_type") or "").lower()
    if ad_id:
        if device == "ios":
            user["idfa"] = str(ad_id)
        elif device == "android":
            user["aaid"] = str(ad_id)
    return user


# --------------------------------------------------------------------------- #
# Public API
# --------------------------------------------------------------------------- #
def send_signup_event(
    data: dict,
    *,
    pixel_id: str,
    access_token: str,
    test_id: str | None = None,
    enabled: bool = True,
    timeout: int = HTTP_TIMEOUT_SECONDS,
) -> dict:
    """
    Send one SignUp conversion event to Reddit.

    Returns:
        {"success": True}                              on 2xx
        {"success": False, "skipped": True}            when disabled/unconfigured
        {"success": False, "error": {...}|"..."}       on HTTP error / exception
    """
    if not enabled or not pixel_id or not access_token:
        return {"success": False, "skipped": True}

    # Never mutate the caller's dict.
    data = dict(data)

    # Rewrite external_id into a unique, time-based event id. "1" == SignUp.
    data["external_id"] = generate_event_id(data.get("external_id") or "anon", "1")

    device = str(data.get("device_type") or "").lower()
    action_source = data.get("action_source") or (
        ACTION_SOURCE_APP if device in ("ios", "android") else ACTION_SOURCE_WEBSITE
    )

    conversion_id = data.get("conversion_id") or generate_conversion_id(
        str(data.get("external_id") or ""), TRACKING_TYPE_SIGNUP
    )

    event = {
        "event_at": _now_ms(),
        "action_source": action_source,
        "type": {"tracking_type": TRACKING_TYPE_SIGNUP},
        "user": _build_user(data),
        "metadata": {"conversion_id": conversion_id},
    }
    if data.get("click_id"):
        event["click_id"] = data["click_id"]

    body = {"data": {"events": [event]}}

    effective_test_id = data.get("test_id") or test_id
    if effective_test_id:
        body["data"]["test_id"] = effective_test_id

    url = ENDPOINT.format(pixel_id=pixel_id)
    try:
        resp = httpx.post(
            url,
            json=body,
            headers={"Authorization": f"Bearer {access_token}"},
            timeout=timeout,
            follow_redirects=True,  # match requests/curl behavior (BE spec uses requests)
        )
        if resp.is_success:  # 2xx
            return {"success": True}
        return {"success": False, "error": {"status": resp.status_code, "body": resp.text}}
    except httpx.HTTPError as exc:
        return {"success": False, "error": str(exc)}
