<?php

namespace Doom\Texture;

use RuntimeException;
use Shufflingpixels\IO\BinaryReader;

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

    public static function parse(BinaryReader $reader): TextureX
    {
        if ($reader->length() < 4) {
            throw new RuntimeException('TEXTUREX lump is too small.');
        }

        $numTextures = $reader->readUInt32LE();

        $offsets = [];
        for ($i = 0; $i < $numTextures; $i++) {
            $offsets[] = $reader->readUInt32LE();
        }

        $textures = [];
        $minimumOffset = 4 + ($numTextures * 4);

        for ($i = 0; $i < $numTextures; $i++) {
            $offset = $offsets[$i];
            if ($offset < $minimumOffset || $offset >= $reader->length()) {
                throw new RuntimeException("Invalid texture offset {$offset} at index {$i}.");
            }

            $reader->seek($offset);

            $name = strtoupper(rtrim($reader->read(8), "\0 "));
            $masked = $reader->readUInt32LE() !== 0;
            $width = $reader->readUInt16LE();
            $height = $reader->readUInt16LE();
            $columnDirectory = $reader->readUInt32LE();
            $patchCount = $reader->readUInt16LE();

            $patches = [];
            for ($patchIndex = 0; $patchIndex < $patchCount; $patchIndex++) {
                $patches[] = new Patch(
                    originX: $reader->readInt16LE(),
                    originY: $reader->readInt16LE(),
                    patch: $reader->readUInt16LE(),
                    stepDir: $reader->readUInt16LE(),
                    colorMap: $reader->readUInt16LE(),
                );
            }

            $textures[] = new TextureDefinition(
                name: $name,
                masked: $masked,
                width: $width,
                height: $height,
                columnDirectory: $columnDirectory,
                patches: $patches,
            );
        }

        return new TextureX($numTextures, $offsets, $textures);
    }
}
