#!/usr/bin/env python3
"""Capture the NDL's public metadata and full-text-search snippets for Er97e.

The digitized issue itself is restricted to NDL/partner-library or registered
personal transmission, but the NDL explicitly permits anonymous snippets.  This
script uses only documented/public HTTPS endpoints and writes their unmodified
JSON/XML responses.  The offline audit in audit_primary_ocr.py verifies and
reconstructs the overlapping OCR passage.
"""

from __future__ import annotations

import datetime as dt
import json
from pathlib import Path
import urllib.parse
import urllib.request

PID = "10996926"
BID = "86617e18-d467-432b-a41c-ffaef86a8d29"
BASE = "https://dl.ndl.go.jp/api"
HERE = Path(__file__).resolve().parent

# Each phrase has one intended match in OCR content index 85 unless noted by the
# audit. Quotes request an exact phrase from the NDL full-text service.
QUERIES = [
    "minimal",
    '"denote by f(t)"',
    '"the number of distances from any points"',
    '"Assume that the distance occurs"',
    '"for largertthe determination"',
    "complicated",
    "really",
    '"But here is a perhaps difficul1"',
    '"Let y1,,large) be any sequence"',
    '"points with di,)1.Is it true"',
    '"hat fornt the number of distances"',
    '"number of distances is less"',
    '"with aquality perhaps only"',
    '"perhaps only for the triangular lattice"',
    '"In particular, is it true that"',
    '"the number f distancesis less"',
    '"This if true"',
    '"can surely be proved but we certainly"',
    '"but we certainly id no"',
    '"Perhaps the following stronger conjecture"',
    '"stronger conjecture holds"',
    '"be the set of distances occurring"',
    '"set of distances occurring in the triangular lattice"',
    '"there is an enso that for every"',
    '"so that for every et"',
    '"for every et y1,,with"',
    '"with dith"',
    '"is less than f"',
]


def get_bytes(url: str) -> bytes:
    req = urllib.request.Request(url, headers={"User-Agent": "source-audit/1.0"})
    with urllib.request.urlopen(req, timeout=120) as response:
        return response.read()


def post_json(url: str, payload: dict) -> tuple[bytes, dict]:
    body = json.dumps(payload, ensure_ascii=False, separators=(",", ":")).encode()
    req = urllib.request.Request(
        url,
        data=body,
        headers={
            "Content-Type": "application/json",
            "User-Agent": "source-audit/1.0",
        },
    )
    with urllib.request.urlopen(req, timeout=120) as response:
        raw = response.read()
    return raw, json.loads(raw)


def main() -> None:
    HERE.mkdir(parents=True, exist_ok=True)

    item_url = f"{BASE}/item/search/info:ndljp/pid/{PID}"
    item_raw = get_bytes(item_url)
    # Parse before writing so an HTTP error page can never become a capture.
    json.loads(item_raw)
    (HERE / "item_api.json").write_bytes(item_raw)

    permission_url = f"{BASE}/check/allowedContents/ooc/snippet"
    permission_raw = get_bytes(permission_url)
    json.loads(permission_raw)
    (HERE / "snippet_permission_api.json").write_bytes(permission_raw)

    sru_params = urllib.parse.urlencode(
        {
            "operation": "searchRetrieve",
            "version": "1.2",
            "query": 'anywhere="Some of my favourite unsolved problems"',
            "maximumRecords": "20",
            "recordSchema": "dcndl",
        }
    )
    sru_url = f"https://ndlsearch.ndl.go.jp/api/sru?{sru_params}"
    (HERE / "ndl_search_sru.xml").write_bytes(get_bytes(sru_url))

    captures = []
    endpoint = f"{BASE}/fulltext/search"
    for query in QUERIES:
        payload = {
            "keyword": query,
            "keywords": [query],
            "targets": [{"pid": PID, "bids": [BID]}],
            "mode": "SNIPPET",
            "sort": "SCORE",
            "size": 10,
            "fullTextInterval": 2,
            "ftInterval": 400,
        }
        raw, response = post_json(endpoint, payload)
        captures.append(
            {
                "query": query,
                "request": payload,
                # Keep the parsed response in a single auditable JSON file.  A
                # canonical re-encoding changes whitespace only, not content.
                "response": response,
            }
        )

    record = {
        "capture_date_utc": dt.datetime.now(dt.timezone.utc).date().isoformat(),
        "institution": "National Diet Library, Japan",
        "pid": PID,
        "item_url": "https://dl.ndl.go.jp/pid/10996926",
        "metadata_api_url": item_url,
        "snippet_api_url": endpoint,
        "sru_api_url": sru_url,
        "captures": captures,
    }
    (HERE / "snippet_api_capture.json").write_text(
        json.dumps(record, ensure_ascii=False, indent=2) + "\n", encoding="utf-8"
    )
    print(f"captured {len(captures)} overlapping snippets for NDL PID {PID}")


if __name__ == "__main__":
    main()
