"""Signal ingestion via a signal-cli JSON-RPC daemon.

signal-cli is NOT containerised by digest-engine — assume a separate compose
service (e.g. `signal-cli`, image `bbernhard/signal-cli-rest-api` or a hand-rolled
`signal-cli daemon --http`) already linked as a secondary device to the real
account, reachable on the compose network at SIGNAL_CLI_URL (e.g.
http://signal-cli:8080). Method names/params follow
https://github.com/AsamK/signal-cli/blob/master/man/signal-cli-jsonrpc.5.adoc

`receive` drains the account's server-side envelope queue. That drain is
protocol-mandated to read anything at all (Signal has no "peek" primitive) and is
the single exception permitted by the read-only rule — it sends no message, sets
no read receipt (`sendReadReceipts` is left at its default off) and mutates no
conversation.
"""

import logging
import os
import uuid
from datetime import datetime, timedelta, timezone

import requests

LOG = logging.getLogger(__name__)

RPC_PATH = "/api/v1/rpc"


def _envelope_to_record(envelope):
    data_message = envelope.get("dataMessage") or {}
    body = data_message.get("message")
    if not body:
        return None
    timestamp_ms = envelope.get("timestamp") or data_message.get("timestamp")
    sent_at = (
        datetime.fromtimestamp(timestamp_ms / 1000, tz=timezone.utc) if timestamp_ms else None
    )
    group_info = data_message.get("groupInfo") or {}
    return {
        "source": "signal",
        "from": envelope.get("sourceName") or envelope.get("sourceNumber") or envelope.get("source"),
        "group": group_info.get("groupName") or group_info.get("groupId"),
        "timestamp": sent_at.isoformat() if sent_at else None,
        "body": body,
    }


def fetch(lookback_hours):
    base_url = os.environ.get("SIGNAL_CLI_URL", "").strip().rstrip("/")
    account = os.environ.get("SIGNAL_ACCOUNT", "").strip()
    timeout = float(os.environ.get("SIGNAL_RECEIVE_TIMEOUT", "10"))

    if not base_url:
        LOG.warning("signal: SIGNAL_CLI_URL not set, skipping")
        return []

    params = {"timeout": timeout, "sendReadReceipts": False}
    if account:
        params["account"] = account

    payload = {
        "jsonrpc": "2.0",
        "id": str(uuid.uuid4()),
        "method": "receive",
        "params": params,
    }

    try:
        response = requests.post(base_url + RPC_PATH, json=payload, timeout=timeout + 15)
        response.raise_for_status()
        result = response.json()
    except Exception:
        LOG.warning("signal: JSON-RPC call to %s failed, returning nothing", base_url, exc_info=True)
        return []

    if "error" in result:
        LOG.warning("signal: daemon returned an error: %s", result["error"])
        return []

    since = datetime.now(timezone.utc) - timedelta(hours=lookback_hours)
    messages = []
    for item in result.get("result") or []:
        try:
            envelope = item.get("envelope") if isinstance(item, dict) else None
            if not envelope:
                continue
            record = _envelope_to_record(envelope)
            if not record:
                continue
            if record["timestamp"] and datetime.fromisoformat(record["timestamp"]) < since:
                continue
            messages.append(record)
        except Exception:
            LOG.warning("signal: could not parse an envelope, skipping", exc_info=True)

    LOG.info("signal: %d message(s) in the last %sh", len(messages), lookback_hours)
    return messages
