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

from __future__ import annotations

import argparse
import json
from pathlib import Path

import pymupdf as fitz
from PIL import Image
from reportlab.graphics import renderPDF
from reportlab.graphics.barcode import code128
from reportlab.graphics.barcode.qr import QrCodeWidget
from reportlab.graphics.shapes import Drawing
from reportlab.lib.colors import HexColor
from reportlab.lib.pagesizes import A4
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas


WIDTH, HEIGHT = A4
FONT_PATHS = (
    Path("/System/Library/Fonts/Supplemental/Arial Unicode.ttf"),
    Path("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"),
)


def register_font() -> str:
    for path in FONT_PATHS:
        if path.exists():
            pdfmetrics.registerFont(TTFont("FixtureSans", str(path)))
            return "FixtureSans"
    return "Helvetica"


def normalized_region(x: float, baseline_y: float, width: float, height: float = 15) -> dict[str, float]:
    y_bottom = baseline_y - 3
    return {
        "x0": round(x / WIDTH, 5),
        "y0": round((HEIGHT - y_bottom - height) / HEIGHT, 5),
        "x1": round((x + width) / WIDTH, 5),
        "y1": round((HEIGHT - y_bottom) / HEIGHT, 5),
    }


def add_text_region(regions: list[dict[str, object]], region_id: str, category: str, x: float, y: float, text: str, font: str, size: int = 11) -> None:
    width = pdfmetrics.stringWidth(text, font, size)
    regions.append(
        {
            "region_id": region_id,
            "category": category,
            "box": normalized_region(x, y, width, size + 5),
            "required_action": "redact",
            "legibility": "clear",
            "notes": "synthetic label only",
        }
    )


def create_pdf(path: Path, annotation_path: Path) -> None:
    font = register_font()
    output = canvas.Canvas(str(path), pagesize=A4, pageCompression=1)
    output.setTitle("Синтетический документ - тест очистки")
    output.setAuthor("Иванов Иван Иванович")
    output.setSubject("synthetic.patient@example.test; +7 999 123-45-67")
    output.setCreator("MIKA synthetic fixture generator")

    pages: list[dict[str, object]] = []

    regions: list[dict[str, object]] = []
    output.setFillColor(HexColor("#173126"))
    output.rect(0, HEIGHT - 90, WIDTH, 90, fill=1, stroke=0)
    output.setFillColor(HexColor("#ffffff"))
    output.setFont(font, 22)
    output.drawString(44, HEIGHT - 55, "СИНТЕТИЧЕСКАЯ МЕДИЦИНСКАЯ ВЫПИСКА")
    output.setFillColor(HexColor("#111111"))
    output.setFont(font, 11)

    rows = [
        ("person_name", "Ф.И.О.: Иванов Иван Иванович"),
        ("birth_date", "Дата рождения: 12.04.1978"),
        ("phone", "Телефон: +7 999 123-45-67"),
        ("email", "Email: synthetic.patient@example.test"),
        ("snils", "СНИЛС: 123-456-789 01"),
        ("insurance_policy", "Полис ОМС: 1234567890123456"),
        ("medical_record_id", "Медицинская карта: MRN-7742-A"),
        ("address", "Адрес проживания: г. Тестоград, ул. Примерная, д. 7, кв. 12"),
    ]
    y = HEIGHT - 125
    for index, (category, text) in enumerate(rows, start=1):
        output.drawString(54, y, text)
        label, value = text.split(":", 1)
        value = value.strip()
        value_x = 54 + pdfmetrics.stringWidth(label + ": ", font, 11)
        add_text_region(regions, f"p1-r{index:02d}", category, value_x, y, value, font)
        y -= 25

    output.setFont(font, 14)
    output.drawString(54, y - 10, "Клиническая информация, которую необходимо сохранить")
    output.setFont(font, 11)
    clinical = [
        "Диагноз: рак молочной железы, стадия IIА.",
        "Гистология: инвазивная карцинома неспецифического типа.",
        "ИГХ: ER 90%, PR 70%, HER2 0, Ki-67 25%.",
        "Лечение: операция, затем адъювантная системная терапия.",
        "Биопсия выполнена 15.08.2026.",
    ]
    y -= 38
    for line in clinical:
        output.drawString(54, y, line)
        if "15.08.2026" in line:
            prefix = line.split("15.08.2026")[0]
            date_x = 54 + pdfmetrics.stringWidth(prefix, font, 11)
            add_text_region(regions, "p1-r09", "event_date", date_x, y, "15.08.2026", font)
            regions[-1]["required_action"] = "review"
        y -= 23

    qr = QrCodeWidget("SYNTHETIC-PATIENT-ID-7742")
    bounds = qr.getBounds()
    qr_size = 82
    drawing = Drawing(qr_size, qr_size, transform=[qr_size / (bounds[2] - bounds[0]), 0, 0, qr_size / (bounds[3] - bounds[1]), 0, 0])
    drawing.add(qr)
    qr_x, qr_y = WIDTH - 140, 64
    renderPDF.draw(drawing, output, qr_x, qr_y)
    regions.append(
        {
            "region_id": "p1-r10",
            "category": "barcode",
            "box": {
                "x0": round(qr_x / WIDTH, 5),
                "y0": round((HEIGHT - qr_y - qr_size) / HEIGHT, 5),
                "x1": round((qr_x + qr_size) / WIDTH, 5),
                "y1": round((HEIGHT - qr_y) / HEIGHT, 5),
            },
            "required_action": "redact",
            "legibility": "clear",
            "notes": "synthetic QR only",
        }
    )
    output.setFont(font, 8)
    output.drawString(54, 40, "Только для синтетических испытаний MIKA De-ID Local")
    output.showPage()
    pages.append({"page": 1, "width": 1.0, "height": 1.0, "regions": regions})

    regions = []
    output.setFont(font, 11)
    y = HEIGHT - 60
    header_text = "Пациент: Иванов Иван Иванович    История болезни: CASE-0007742"
    output.drawString(44, y, header_text)
    name_prefix = "Пациент: "
    name_x = 44 + pdfmetrics.stringWidth(name_prefix, font, 11)
    add_text_region(regions, "p2-r01", "person_name", name_x, y, "Иванов Иван Иванович", font)
    record_prefix = "Пациент: Иванов Иван Иванович    История болезни: "
    record_x = 44 + pdfmetrics.stringWidth(record_prefix, font, 11)
    add_text_region(regions, "p2-r02", "medical_record_id", record_x, y, "CASE-0007742", font)

    output.setFont(font, 15)
    output.drawString(44, y - 45, "Лабораторные показатели")
    output.setFont(font, 11)
    values = [
        "Гемоглобин: 121 г/л",
        "Лейкоциты: 5,8 x10^9/л",
        "Тромбоциты: 248 x10^9/л",
        "Креатинин: 72 мкмоль/л",
        "АЛТ: 24 Ед/л",
    ]
    line_y = y - 80
    for value in values:
        output.drawString(64, line_y, value)
        line_y -= 25

    barcode = code128.Code128("SYNTHETIC-CASE-0007742", barHeight=38, barWidth=0.65, humanReadable=False)
    barcode_x, barcode_y = 54, 90
    barcode.drawOn(output, barcode_x, barcode_y)
    regions.append(
        {
            "region_id": "p2-r03",
            "category": "barcode",
            "box": {
                "x0": round(barcode_x / WIDTH, 5),
                "y0": round((HEIGHT - barcode_y - 42) / HEIGHT, 5),
                "x1": round((barcode_x + barcode.width) / WIDTH, 5),
                "y1": round((HEIGHT - barcode_y) / HEIGHT, 5),
            },
            "required_action": "redact",
            "legibility": "clear",
            "notes": "synthetic Code 128 only",
        }
    )
    output.setFont(font, 8)
    output.drawString(44, 40, "Только для синтетических испытаний MIKA De-ID Local")
    output.showPage()
    pages.append({"page": 2, "width": 1.0, "height": 1.0, "regions": regions})
    output.save()

    annotation = {
        "schema": "mika-deid-annotation-v1",
        "document_id": "doc-synthetic-0001",
        "pages": pages,
    }
    annotation_path.write_text(json.dumps(annotation, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")


def create_photo(pdf_path: Path, image_path: Path) -> None:
    document = fitz.open(pdf_path)
    try:
        page = document.load_page(0)
        pixmap = page.get_pixmap(matrix=fitz.Matrix(2.0, 2.0), alpha=False, colorspace=fitz.csRGB)
        image = Image.frombytes("RGB", (pixmap.width, pixmap.height), pixmap.samples)
        exif = Image.Exif()
        exif[0x010E] = "Synthetic patient document"
        exif[0x013B] = "Иванов Иван Иванович"
        image.save(image_path, format="JPEG", quality=87, exif=exif)
    finally:
        document.close()


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("output_dir", type=Path)
    args = parser.parse_args()
    args.output_dir.mkdir(parents=True, exist_ok=True)
    pdf_path = args.output_dir / "doc-synthetic-0001.pdf"
    annotation_path = args.output_dir / "doc-synthetic-0001.annotation.json"
    image_path = args.output_dir / "doc-synthetic-photo-0002.jpg"
    create_pdf(pdf_path, annotation_path)
    create_photo(pdf_path, image_path)
    print(json.dumps({"pdf": str(pdf_path), "annotation": str(annotation_path), "photo": str(image_path)}, ensure_ascii=False))
    return 0


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