<?php

namespace Doom\Picture;

use InvalidArgumentException;
use RuntimeException;
use Shufflingpixels\IO\BinaryReader;

final class PictureParser
{
    public static function parseBytes(string $data): Picture
    {
        return self::parse(BinaryReader::string($data));
    }

    public static function parse(BinaryReader $reader): Picture
    {
        if ($reader->length() < 8) {
            throw new InvalidArgumentException('Picture lump is too small.');
        }

        $width = $reader->readUInt16LE();
        $height = $reader->readUInt16LE();
        $left = $reader->readInt16LE();
        $top = $reader->readInt16LE();

        if ($width <= 0 || $height <= 0) {
            throw new InvalidArgumentException('Picture dimensions must be greater than zero.');
        }

        $columnDirectoryBytes = $width * 4;

        $columnOffsets = [];
        for ($x = 0; $x < $width; $x++) {
            $columnOffsets[] = $reader->readUInt32LE();
        }

        $headerSize = 8 + $columnDirectoryBytes;
        $posts = [];

        for ($x = 0; $x < $width; $x++) {
            $offset = $columnOffsets[$x];
            if ($offset < $headerSize || $offset >= $reader->length()) {
                throw new RuntimeException("Invalid column offset {$offset} for column {$x}.");
            }

            $reader->seek($offset);

            $columnPosts = [];
            $previousY = -1;

            while (true) {
                if ($reader->eof()) {
                    throw new RuntimeException("Missing column terminator for column {$x}.");
                }

                $topDelta = $reader->readUInt8();
                if ($topDelta === 0xFF) {
                    break;
                }

                $length = $reader->readUInt8();
                $reader->readUInt8();

                $pixels = [];
                for ($i = 0; $i < $length; $i++) {
                    $pixels[] = $reader->readUInt8();
                }

                $reader->readUInt8();

                $y = $topDelta;
                if ($previousY !== -1 && $topDelta <= $previousY) {
                    $y = $previousY + 1 + $topDelta;
                }

                $previousY = $y;

                $columnPosts[] = [
                    'y' => $y,
                    'topdelta' => $topDelta,
                    'pixels' => $pixels,
                ];
            }

            $posts[$x] = $columnPosts;
        }

        return new Picture($width, $height, $left, $top, $posts);
    }
}
