"""Private stdin/stdout image conversion. Invoked in a short-lived child only.

No original image files, web addresses, customer records or credentials enter
this process. Its caller supervises time, resident memory and output size.
"""
import io
import json
import sys
import warnings

MAX_FILE_BYTES = 10 * 1024 * 1024
MAX_PIXELS = 12_000_000
MAX_SIDE = 12000
MAX_EDGE = 1800
MAX_OUTPUT_BYTES = 13 * 1024 * 1024
FORMATS = ('PNG', 'JPEG', 'WEBP', 'HEIF')


class Rejected(Exception):
    pass


def convert(raw):
    # Registration stays inside this child: authenticated photo/asset upload
    # routes retain their existing formats and size rules.
    from PIL import Image, ImageOps
    import pillow_heif
    Image.MAX_IMAGE_PIXELS = MAX_PIXELS
    warnings.simplefilter('error', Image.DecompressionBombWarning)
    pillow_heif.register_heif_opener(thumbnails=False, depth_images=False,
                                    aux_images=False, decode_threads=1)
    pillow_heif.options.DISABLE_SECURITY_LIMITS = False
    if not raw or len(raw) > MAX_FILE_BYTES:
        raise Rejected('size')
    with Image.open(io.BytesIO(raw), formats=FORMATS) as source:
        source_format = source.format
        if source_format == 'HEIF' and pillow_heif.get_file_mimetype(raw) not in ('image/heic', 'image/heif'):
            raise Rejected('frames')
        if getattr(source, 'n_frames', 1) != 1:
            raise Rejected('frames')
        if source.width * source.height > MAX_PIXELS or max(source.size) > MAX_SIDE:
            raise Rejected('dimensions')
        source.verify()
    with Image.open(io.BytesIO(raw), formats=FORMATS) as source:
        source.load()
        # HEIF applies container transforms during decode and resets EXIF
        # orientation; exif_transpose handles ordinary JPEG/PNG orientation.
        oriented = ImageOps.exif_transpose(source)
        oriented.thumbnail((MAX_EDGE, MAX_EDGE))
        clean = Image.new('RGBA', oriented.size)
        clean.paste(oriented.convert('RGBA'))
        output = io.BytesIO()
        clean.save(output, 'PNG')
        body = output.getvalue()
        if len(body) > MAX_OUTPUT_BYTES:
            raise Rejected('output')
        return {'ok': True, 'format': source_format, 'width': clean.width,
                'height': clean.height, 'bytes': len(body)}, body


def main():
    try:
        import resource
        resource.setrlimit(resource.RLIMIT_CPU, (10, 10))
        resource.setrlimit(resource.RLIMIT_FSIZE, (MAX_OUTPUT_BYTES + 4096,) * 2)
        # macOS does not offer a usable RLIMIT_AS here. The parent therefore
        # also monitors child RSS; its sampling is not a hard OS memory quota.
        if sys.platform.startswith('linux'):
            resource.setrlimit(resource.RLIMIT_AS, (1024 * 1024 * 1024,) * 2)
        raw = sys.stdin.buffer.read(MAX_FILE_BYTES + 1)
        result, body = convert(raw)
    except ImportError:
        result, body = {'ok': False, 'error': 'unavailable'}, b''
    except Rejected as error:
        result, body = {'ok': False, 'error': str(error)}, b''
    except Exception:
        # Never echo native exception strings, original metadata or bytes.
        result, body = {'ok': False, 'error': 'unsupported'}, b''
    sys.stdout.buffer.write(json.dumps(result).encode() + b'\n' + body)


if __name__ == '__main__':
    main()
