"""Map evidence packets with DeepSeek via OpenRouter; retain an audit per call."""

import argparse
import concurrent.futures
import hashlib
import json
import os
import time
import urllib.error
import urllib.request
from datetime import UTC, datetime
from pathlib import Path

from dataset import mapping_prompt, pilot_cases, plot_run, save_run

MODEL = "deepseek/deepseek-v4.1-flash"
API = "https://openrouter.ai/api/v1"


def request_json(path, payload=None, authenticated=False):
    headers = {"Content-Type": "application/json"}
    if payload is not None or authenticated:
        key = os.environ.get("OPENROUTER_API_KEY") or os.environ.get("openrouter")
        if not key:
            raise RuntimeError(
                "Set OPENROUTER_API_KEY or the existing openrouter variable"
            )
        headers["Authorization"] = "Bearer " + key.strip()
    request = urllib.request.Request(
        API + path,
        data=json.dumps(payload).encode() if payload is not None else None,
        headers=headers,
    )
    with urllib.request.urlopen(request, timeout=180) as response:
        result = json.load(response)
    if "error" in result:
        raise RuntimeError("OpenRouter returned an API error")
    return result


def generate_one(record, directory, model):
    path = directory / (record["input"]["case_id"] + ".json")
    prompt = mapping_prompt(record)
    digest = hashlib.sha256(prompt.encode()).hexdigest()
    if path.exists():
        saved = json.loads(path.read_text())
        if saved["prompt_sha256"] != digest or saved["requested_model"] != model:
            raise ValueError("Cached response belongs to a different prompt/model")
        return saved
    started = time.monotonic()
    # Never automatically repeat a POST with an unknown outcome or charge.
    response = request_json(
        "/chat/completions",
        {
            "model": model,
            "messages": [{"role": "user", "content": prompt}],
            "temperature": 0,
            "max_tokens": 4096,
            "reasoning": {"enabled": False},
            "response_format": {"type": "json_object"},
            "provider": {"allow_fallbacks": False},
            "usage": {"include": True},
        },
    )
    result = {
        "text": response["choices"][0]["message"]["content"],
        "finish_reason": response["choices"][0]["finish_reason"],
        "response_id": response["id"],
        "requested_model": model,
        "returned_model": response.get("model"),
        "provider": response.get("provider"),
        "usage": response.get("usage", {}),
        "seconds": round(time.monotonic() - started, 2),
        "prompt_sha256": digest,
        "created_at": datetime.now(UTC).isoformat(),
    }
    path.write_text(json.dumps(result, indent=2))
    return result


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--model", default=MODEL)
    parser.add_argument("--per-scenario", type=int, default=2)
    parser.add_argument("--seed", type=int, default=42)
    parser.add_argument("--output", default="data/deepseek-pilot-001")
    args = parser.parse_args()
    if not 1 <= args.per_scenario <= 10:
        raise ValueError("Pilot limited to 1..10 variants per scenario")
    output = Path(args.output)
    if output.exists():
        raise FileExistsError("Run output already exists; use a new directory")
    cache = output.with_name(output.name + "-responses")
    cache.mkdir(parents=True, exist_ok=True)
    catalog = request_json("/models")
    model_info = next(m for m in catalog["data"] if m["id"] == args.model)
    records = list(pilot_cases(args.seed, args.per_scenario))
    started = time.monotonic()
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as pool:
        results = list(
            pool.map(lambda record: generate_one(record, cache, args.model), records)
        )
    runtime = {
        "model": args.model,
        "catalog_entry": model_info,
        "seed": args.seed,
        "temperature": 0,
        "max_tokens": 4096,
        "seconds": round(time.monotonic() - started, 2),
        "total_reported_cost_usd": sum(r["usage"].get("cost", 0) or 0 for r in results),
        "run_at": datetime.now(UTC).isoformat(),
    }
    report = save_run(records, results, output, runtime)
    plot_run(report, str(output / "dataset.png"))
    print(json.dumps({k: v for k, v in report.items() if k != "runtime"}, indent=2))
    print("Reported API cost USD:", runtime["total_reported_cost_usd"])


if __name__ == "__main__":
    main()
