import re
import subprocess
import sys


def run_bytes(args):
    try:
        return subprocess.run(args, check=True, stdout=subprocess.PIPE).stdout
    except FileNotFoundError:
        sys.exit(f"missing required command: {args[0]}")
    except subprocess.CalledProcessError as exc:
        sys.exit(f"command failed ({exc.returncode}): {' '.join(args)}")


def run_text(args):
    return run_bytes(args).decode("utf-8", "replace")


def parse_ppm(data):
    idx = 0

    def next_token():
        nonlocal idx
        while idx < len(data) and data[idx] in b" \t\r\n":
            idx += 1
        if idx < len(data) and data[idx] == ord("#"):
            while idx < len(data) and data[idx] not in b"\r\n":
                idx += 1
            return next_token()
        start = idx
        while idx < len(data) and data[idx] not in b" \t\r\n":
            idx += 1
        return data[start:idx]

    magic = next_token()
    if magic != b"P6":
        sys.exit("ImageMagick did not return binary PPM data")

    width = int(next_token())
    height = int(next_token())
    max_value = int(next_token())
    if max_value != 255:
        sys.exit(f"unsupported PPM max value: {max_value}")

    while idx < len(data) and data[idx] in b" \t\r\n":
        idx += 1

    return width, height, data[idx:]


def ppm_from_magick(args):
    return parse_ppm(run_bytes(["magick", *args, "-alpha", "off", "-depth", "8", "ppm:-"]))


def try_ppm_from_magick(args):
    command = ["magick", *args, "-alpha", "off", "-depth", "8", "ppm:-"]
    try:
        result = subprocess.run(command, check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    except FileNotFoundError:
        sys.exit("missing required command: magick")

    if result.returncode != 0:
        return None, result.stderr.decode("utf-8", "replace").strip()

    try:
        return parse_ppm(result.stdout), ""
    except Exception as exc:
        return None, str(exc)


def magick_fonts():
    fonts = set()
    for line in run_text(["magick", "-list", "font"]).splitlines():
        match = re.match(r"\s*Font:\s*(\S+)", line)
        if match:
            fonts.add(match.group(1))
    return fonts


def image_size(image_path):
    output = run_bytes(["magick", "identify", "-format", "%w %h", image_path]).decode("ascii")
    width, height = output.split()
    return int(width), int(height)
