from __future__ import annotations

import argparse
import json
from typing import Any

from embed_1c_semantic_cache import DEFAULT_ADAPTER_URL, adapter_call, embed_pending_semantic_cache
from rag_embedding_providers import LOCAL_HASHING_MODEL, LOCAL_HASHING_PROVIDER, embed_texts, provider_metadata


def search_semantic_cache(
    *,
    adapter_url: str,
    base_id: str,
    query: str,
    kind: str = "",
    limit: int = 20,
    scan_limit: int = 1000,
    embedding_provider: str = LOCAL_HASHING_PROVIDER,
    embedding_model: str = LOCAL_HASHING_MODEL,
    dimensions: int = 384,
    embedding_base_url: str = "",
    embedding_api_key_env: str = "OPENAI_API_KEY",
    validate_candidates: bool = False,
    validation_limit: int | None = None,
    embed_pending: bool = False,
    embed_limit: int = 100,
    embed_batch_size: int = 16,
    timeout_seconds: int = 180,
) -> dict[str, Any]:
    embed_result = None
    if embed_pending:
        embed_result = embed_pending_semantic_cache(
            adapter_url=adapter_url,
            base_id=base_id,
            kind=kind,
            limit=embed_limit,
            batch_size=embed_batch_size,
            embedding_provider=embedding_provider,
            embedding_model=embedding_model,
            dimensions=dimensions,
            embedding_base_url=embedding_base_url,
            embedding_api_key_env=embedding_api_key_env,
            timeout_seconds=timeout_seconds,
        )
    query_embedding = embed_texts(
        [query],
        provider=embedding_provider,
        model=embedding_model,
        dimensions=dimensions,
        base_url=embedding_base_url,
        api_key_env=embedding_api_key_env,
    )[0]
    payload: dict[str, Any] = {
        "base_id": base_id,
        "query": query,
        "query_embedding": query_embedding,
        "limit": limit,
        "scan_limit": scan_limit,
        "validate_candidates": validate_candidates,
    }
    if kind:
        payload["kind"] = kind
    if validation_limit is not None:
        payload["validation_limit"] = validation_limit
    result = adapter_call(adapter_url, "semantic.cache.search", payload, timeout_seconds=timeout_seconds)
    result.setdefault("client_embedding", {})
    result["client_embedding"] = {
        "provider": provider_metadata(provider=embedding_provider, model=embedding_model, dimensions=len(query_embedding), base_url=embedding_base_url).get("embedding_provider"),
        "model": embedding_model,
        "dimensions": len(query_embedding),
    }
    if embed_result is not None:
        result["embedding_refresh"] = {
            "status": embed_result.get("status"),
            "counts": embed_result.get("counts") or {},
            "embedding": embed_result.get("embedding") or {},
        }
    return result


def print_match(match: dict[str, Any], position: int) -> None:
    obj = match.get("object") or {}
    cache = match.get("cache") or {}
    print(f"{position}. score={float(match.get('score') or 0):.4f} match_by={match.get('match_by')}")
    print(f"   object={obj.get('kind')} {obj.get('name') or obj.get('guid')}")
    print(f"   document_id={match.get('document_id')}")
    print(f"   embedding_model={cache.get('embedding_model')} vector_status={cache.get('vector_status')}")
    text = str(match.get("text_preview") or "").replace("\n", " ").strip()
    if len(text) > 500:
        text = text[:497].rstrip() + "..."
    print(f"   text={text}")


def main() -> int:
    parser = argparse.ArgumentParser(description="Search the 1C adapter semantic cache with a computed query embedding.")
    parser.add_argument("query")
    parser.add_argument("--adapter-url", default=DEFAULT_ADAPTER_URL)
    parser.add_argument("--base-id", required=True)
    parser.add_argument("--kind", default="")
    parser.add_argument("--limit", type=int, default=20)
    parser.add_argument("--scan-limit", type=int, default=1000)
    parser.add_argument("--embedding-provider", default=LOCAL_HASHING_PROVIDER, choices=[LOCAL_HASHING_PROVIDER, "openai-compatible"])
    parser.add_argument("--embedding-model", default=LOCAL_HASHING_MODEL)
    parser.add_argument("--dimensions", type=int, default=384)
    parser.add_argument("--embedding-base-url", default="")
    parser.add_argument("--embedding-api-key-env", default="OPENAI_API_KEY")
    parser.add_argument("--validate-candidates", action="store_true")
    parser.add_argument("--validation-limit", type=int)
    parser.add_argument("--embed-pending", action="store_true")
    parser.add_argument("--embed-limit", type=int, default=100)
    parser.add_argument("--embed-batch-size", type=int, default=16)
    parser.add_argument("--timeout-seconds", type=int, default=180)
    parser.add_argument("--json", action="store_true")
    args = parser.parse_args()

    result = search_semantic_cache(
        adapter_url=args.adapter_url,
        base_id=args.base_id,
        query=args.query,
        kind=args.kind,
        limit=args.limit,
        scan_limit=args.scan_limit,
        embedding_provider=args.embedding_provider,
        embedding_model=args.embedding_model,
        dimensions=args.dimensions,
        embedding_base_url=args.embedding_base_url,
        embedding_api_key_env=args.embedding_api_key_env,
        validate_candidates=args.validate_candidates,
        validation_limit=args.validation_limit,
        embed_pending=args.embed_pending,
        embed_limit=args.embed_limit,
        embed_batch_size=args.embed_batch_size,
        timeout_seconds=args.timeout_seconds,
    )
    if args.json:
        print(json.dumps(result, ensure_ascii=False, indent=2))
    elif result.get("matches"):
        print(f"semantic_cache_status={result.get('status')} matches={len(result.get('matches') or [])}")
        for position, match in enumerate(result.get("matches") or [], start=1):
            print_match(match, position)
    else:
        print(f"No matches. status={result.get('status')} error={result.get('error')}")
    return 0 if result.get("status") == "ok" else 1


if __name__ == "__main__":
    raise SystemExit(main())
