"""Apply API mark operations to the exact source. Python 3.10+."""
import json
import os
import re
import sys
import unicodedata
from urllib.error import HTTPError
from urllib.request import Request, urlopen


ARABIC_MARKS = re.compile(r"^[\u0610-\u061a\u064b-\u065f\u0670\u06d6-\u06ed]+$")


def apply_operations(source, operations):
    additions = {}
    for operation in operations:
        index, mark = operation["source_index"], operation["mark"]
        if type(index) is not int or not 0 <= index < len(source):
            raise ValueError("Mark operation has an invalid source index")
        character = source[index]
        is_arabic_letter = (
            unicodedata.category(character).startswith("L")
            and unicodedata.name(character, "").startswith("ARABIC ")
            and character != "\u0640"  # Tatweel is a joining extender, not a source letter.
        )
        if not is_arabic_letter or not isinstance(mark, str) or not ARABIC_MARKS.fullmatch(mark):
            raise ValueError("Operation must attach an Arabic mark to an Arabic-script letter")
        marks = additions.setdefault(index, [])
        if mark not in marks:
            marks.append(mark)
    return "".join(character + "".join(additions.get(index, []))
                   for index, character in enumerate(source))


def checked_reading(source, result):
    if result["original"] != source:
        raise ValueError("The API original does not match the submitted text")
    reconstructed = apply_operations(source, result["operations"])
    if reconstructed != result["marked"]:
        raise ValueError("Marked text does not match the documented operations")
    return reconstructed


def diacritize(source, request_id, include_ezafe=True):
    base = os.environ.get("VOWELMARKS_API_BASE_URL", "https://api.vowelmarks.com")
    payload = {"text": source, "include_ezafe": include_ezafe}
    request = Request(
        base.rstrip("/") + "/v1/diacritize",
        data=json.dumps(payload, ensure_ascii=False).encode("utf-8"), method="POST",
        headers={
            "Authorization": "Bearer " + os.environ["VOWELMARKS_API_KEY"],
            "Content-Type": "application/json", "Idempotency-Key": request_id,
        },
    )
    try:
        with urlopen(request, timeout=120) as response:
            result = json.load(response)
    except HTTPError as error:
        detail = json.loads(error.read()).get("error", {})
        raise RuntimeError(
            f"HTTP {error.code}: {detail.get('code', 'api_error')}; "
            f"retryable={detail.get('retryable', False)}; "
            f"Retry-After={error.headers.get('Retry-After', 'not supplied')}"
        ) from None
    return checked_reading(source, result)


if __name__ == "__main__":
    if len(sys.argv) != 2:
        raise SystemExit("Usage: python3 persian-diacritics.py script.txt")
    with open(sys.argv[1], encoding="utf-8", newline="") as file:
        source = file.read()
    print(diacritize(source, os.environ["VOWELMARKS_REQUEST_ID"]))
