import json
import sys
from pathlib import Path

import cv2


def best_match(template, pages):
    best = None
    for page_path in pages:
        page = cv2.imread(str(page_path), cv2.IMREAD_GRAYSCALE)
        if page is None:
            continue
        for scale in (1.55, 1.65, 1.75, 1.83, 1.9, 2.0):
            resized = cv2.resize(template, None, fx=scale, fy=scale, interpolation=cv2.INTER_CUBIC)
            if resized.shape[0] >= page.shape[0] or resized.shape[1] >= page.shape[1]:
                continue
            result = cv2.matchTemplate(page, resized, cv2.TM_CCOEFF_NORMED)
            _, score, _, location = cv2.minMaxLoc(result)
            candidate = (float(score), page_path, location, resized.shape[1], resized.shape[0], scale)
            if best is None or candidate[0] > best[0]:
                best = candidate
    return best


def main() -> int:
    if len(sys.argv) < 5:
        print("usage: extract_high_res_question.py TEMPLATE OUTPUT PAGE PAGE")
        return 2

    template = cv2.imread(sys.argv[1], cv2.IMREAD_GRAYSCALE)
    if template is None:
        raise RuntimeError("template is unreadable")

    output = Path(sys.argv[2])
    pages = [Path(value) for value in sys.argv[3:]]
    match = best_match(template, pages)
    if match is None:
        return 1

    score, page_path, (x, y), width, height, scale = match
    color_page = cv2.imread(str(page_path), cv2.IMREAD_COLOR)
    padding = max(8, round(8 * scale))
    x1, y1 = max(0, x - padding), max(0, y - padding)
    x2, y2 = min(color_page.shape[1], x + width + padding), min(color_page.shape[0], y + height + padding)
    crop = color_page[y1:y2, x1:x2]
    output.parent.mkdir(parents=True, exist_ok=True)
    cv2.imwrite(str(output), crop, [cv2.IMWRITE_PNG_COMPRESSION, 6])
    print(json.dumps({
        "score": score,
        "page": str(page_path),
        "x": x1,
        "y": y1,
        "width": x2 - x1,
        "height": y2 - y1,
        "scale": scale,
        "output": str(output),
    }))
    return 0


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