import argparse
import json
import math
from pathlib import Path


def ordered_vectors(response, count, model):
    if not isinstance(response, dict) or response.get("model") != model:
        raise ValueError("Unexpected embedding model")
    data = response.get("data")
    if not isinstance(data, list) or len(data) != count:
        raise ValueError("Embedding count mismatch")
    mapped = {}
    dimension = None
    for item in data:
        if not isinstance(item, dict):
            raise ValueError("Invalid embedding item")
        index, vector = item.get("index"), item.get("embedding")
        if type(index) is not int or not 0 <= index < count or index in mapped:
            raise ValueError("Duplicate or invalid embedding index")
        if not isinstance(vector, list) or not vector or any(type(value) not in (int, float) or not math.isfinite(value) for value in vector):
            raise ValueError("Invalid embedding values")
        if dimension is None:
            dimension = len(vector)
        norm = math.hypot(*vector)
        if len(vector) != dimension or norm == 0 or not math.isfinite(norm):
            raise ValueError("Dimension mismatch or zero vector")
        mapped[index] = vector
    return [mapped[index] for index in range(count)]


def cosine(left, right):
    if len(left) != len(right) or not left:
        raise ValueError("Dimension mismatch")
    norms = math.hypot(*left), math.hypot(*right)
    if any(value == 0 or not math.isfinite(value) for value in norms):
        raise ValueError("Invalid norm")
    return sum((a / norms[0]) * (b / norms[1]) for a, b in zip(left, right))


def check_embedding(request, response, fixture):
    documents, queries = fixture["documents"], fixture["queries"]
    if len({item["id"] for item in documents}) != len(documents):
        raise ValueError("Duplicate document ID")
    inputs = [item["text"] for item in documents] + [item["text"] for item in queries]
    if request.get("input") != inputs or request.get("encoding_format") != "float":
        raise ValueError("Request and fixture do not match")
    vectors = ordered_vectors(response, len(inputs), request["model"])
    rankings = []
    for index, query in enumerate(queries):
        scores = sorted([{"document_id": doc["id"], "score": round(cosine(vectors[len(documents) + index], vectors[i]), 6)} for i, doc in enumerate(documents)], key=lambda row: row["score"], reverse=True)
        rankings.append({"query_id": query["id"], "query": query["text"], "ranking": scores, "expected_id": query["expected_id"], "passed": scores[0]["document_id"] == query["expected_id"]})
    return {"model": request["model"], "vector_count": len(vectors), "dimension": len(vectors[0]), "rankings": rankings, "passed": all(row["passed"] for row in rankings), "scope": "Offline replay of supplied evidence; not an API request or a general accuracy benchmark"}


def map_rerank(request, response, fixture):
    documents = fixture["documents"]
    if len({item["id"] for item in documents}) != len(documents):
        raise ValueError("Duplicate document ID")
    if request.get("documents") != [item["text"] for item in documents]:
        raise ValueError("Rerank documents and fixture do not match")
    count = request.get("top_n")
    if type(count) is not int or not 1 <= count <= len(documents):
        raise ValueError("Invalid top_n")
    results = response.get("results") if isinstance(response, dict) else None
    if not isinstance(results, list) or len(results) != count:
        raise ValueError("Expected results with exactly top_n items")
    seen, previous, rows = set(), math.inf, []
    for item in results:
        if not isinstance(item, dict):
            raise ValueError("Invalid rerank item")
        index, score = item.get("index"), item.get("relevance_score")
        if type(index) is not int or not 0 <= index < len(documents) or index in seen or type(score) not in (int, float) or not math.isfinite(score) or score > previous:
            raise ValueError("Invalid index, score or rank order")
        seen.add(index)
        previous = score
        rows.append({"original_index": index, "document_id": documents[index]["id"], "score": score})
    return {"model": request["model"], "query": request["query"], "ranking": rows, "scope": "Original-index mapping; score is not a probability of factual correctness"}


def main():
    parser = argparse.ArgumentParser(description="Offline replay only: no credentials or network requests")
    parser.add_argument("operation", choices=["embedding", "rerank"])
    parser.add_argument("request", type=Path)
    parser.add_argument("response", type=Path)
    parser.add_argument("fixture", type=Path)
    args = parser.parse_args()
    read = lambda path: json.loads(path.read_text(encoding="utf-8"))
    function = check_embedding if args.operation == "embedding" else map_rerank
    result = function(read(args.request), read(args.response), read(args.fixture))
    print(json.dumps(result, ensure_ascii=False, indent=2))
    if result.get("passed") is False:
        raise SystemExit(1)


if __name__ == "__main__":
    main()
