# Copyright (C) 2026 NPO NT
# SPDX-License-Identifier: AGPL-3.0-only

from __future__ import annotations

import argparse
import hashlib
import json
import sys
from pathlib import Path

import pymupdf as fitz
import PIL
import pypdf

from . import __version__
from .analyzer import analyze_document
from .barcodes import barcode_available
from .loader import DocumentLoadError, heif_available, load_document
from .legal import COPYRIGHT_NOTICE, LICENSE_ID, legal_notice
from .ocr import TesseractOcr, project_tessdata_dir
from .verifier import verify_raster_pdf


def _model_hashes() -> dict[str, str]:
    hashes: dict[str, str] = {}
    for model in sorted(project_tessdata_dir().glob("*.traineddata")):
        digest = hashlib.sha256()
        with model.open("rb") as stream:
            for chunk in iter(lambda: stream.read(1024 * 1024), b""):
                digest.update(chunk)
        hashes[model.name] = digest.hexdigest()
    return hashes


def doctor_command(_args: argparse.Namespace) -> int:
    ocr = TesseractOcr()
    payload = {
        "application": "MIKA De-ID Local",
        "version": __version__,
        "status": "LOCAL_SYNTHETIC_ONLY",
        "copyright": COPYRIGHT_NOTICE,
        "license": LICENSE_ID,
        "corresponding_source_in_release_bundle": True,
        "python": sys.version.split()[0],
        "pillow": PIL.__version__,
        "pymupdf": fitz.__version__,
        "pypdf": pypdf.__version__,
        "tesseract_executable": ocr.executable or None,
        "ocr_languages": list(ocr.available_languages),
        "ocr_selected_languages": list(ocr.selected_languages),
        "barcode_available": barcode_available(),
        "heif_available": heif_available(),
        "model_sha256": _model_hashes(),
        "network_required_for_processing": False,
    }
    print(json.dumps(payload, ensure_ascii=False, indent=2))
    return 0 if ocr.available and "rus" in ocr.selected_languages and barcode_available() else 2


def analyze_command(args: argparse.Namespace) -> int:
    try:
        document = load_document(args.input)
        result = analyze_document(document)
    except DocumentLoadError as exc:
        print(json.dumps({"error": str(exc)}, ensure_ascii=False), file=sys.stderr)
        return 2
    print(json.dumps(result.public_dict(), ensure_ascii=False, indent=2))
    return 0 if result.capabilities.complete else 3


def verify_command(args: argparse.Namespace) -> int:
    result = verify_raster_pdf(args.input, expected_page_count=args.pages)
    print(json.dumps(result.as_dict(), ensure_ascii=False, indent=2))
    return 0 if result.passed else 4


def gui_command(_args: argparse.Namespace) -> int:
    from .gui import main as gui_main

    gui_main()
    return 0


def license_command(_args: argparse.Namespace) -> int:
    print(legal_notice())
    return 0


def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        prog="mika-deid",
        description="Offline review-first medical document de-identification product",
    )
    parser.add_argument("--version", action="version", version=__version__)
    subparsers = parser.add_subparsers(dest="command", required=True)

    doctor = subparsers.add_parser("doctor", help="Check local runtime capabilities without opening a document")
    doctor.set_defaults(func=doctor_command)

    analyze = subparsers.add_parser("analyze", help="Analyze a document and emit a log-safe JSON report")
    analyze.add_argument("input", type=Path)
    analyze.set_defaults(func=analyze_command)

    verify = subparsers.add_parser("verify", help="Verify an already sanitized raster PDF")
    verify.add_argument("input", type=Path)
    verify.add_argument("--pages", type=int, required=True, help="Expected page count")
    verify.set_defaults(func=verify_command)

    gui = subparsers.add_parser("gui", help="Launch the page-by-page review interface")
    gui.set_defaults(func=gui_command)

    licence = subparsers.add_parser("license", help="Show copyright, AGPL, and Corresponding Source notice")
    licence.set_defaults(func=license_command)
    return parser


def main(argv: list[str] | None = None) -> int:
    parser = build_parser()
    args = parser.parse_args(argv)
    return int(args.func(args))


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