"""Request fingerprinting utilities for comparing RLM inputs."""

from __future__ import annotations

import hashlib
import json
import os
import sys
from typing import Any


def _sha256(value: str) -> str:
    return hashlib.sha256(value.encode("utf-8")).hexdigest()


def _stat_info(path: str | None) -> dict[str, Any]:
    if not path:
        return {"path": None, "exists": False, "size": None, "mtime": None}
    try:
        stat = os.stat(path)
        return {
            "path": path,
            "exists": True,
            "size": stat.st_size,
            "mtime": stat.st_mtime,
        }
    except FileNotFoundError:
        return {"path": path, "exists": False, "size": None, "mtime": None}


def build_request_fingerprint(
    *,
    question: str,
    db_path: str,
    contacts_db_path: str | None,
    conversation_context: str | None,
    max_depth: int,
    max_calls: int,
    max_output_chars: int,
    root_model: str,
    subcall_model: str,
) -> dict[str, Any]:
    context = conversation_context or ""
    db_info = _stat_info(db_path)
    contacts_info = _stat_info(contacts_db_path)
    return {
        "question_hash": _sha256(question),
        "question_length": len(question),
        "context_hash": _sha256(context) if context else None,
        "context_length": len(context),
        "db_path": db_info["path"],
        "db_exists": db_info["exists"],
        "db_size": db_info["size"],
        "db_mtime": db_info["mtime"],
        "contacts_path": contacts_info["path"],
        "contacts_exists": contacts_info["exists"],
        "contacts_size": contacts_info["size"],
        "contacts_mtime": contacts_info["mtime"],
        "root_model": root_model,
        "subcall_model": subcall_model,
        "max_depth": max_depth,
        "max_calls": max_calls,
        "max_output_chars": max_output_chars,
    }


def log_fingerprint(fingerprint: dict[str, Any], stream: Any = sys.stderr) -> None:
    payload = {"message": "rlm_request_fingerprint", **fingerprint}
    stream.write(json.dumps(payload, ensure_ascii=True) + "\n")
    stream.flush()
