<?php

namespace Doom\Wad;

use Doom\Wad\Exception\InvalidWadException;
use Doom\Wad\Types\Header;
use Doom\Wad\Types\Lump;
use OutOfBoundsException;
use Shufflingpixels\IO\BinaryReader;

class Parser
{
    public function __construct(protected BinaryReader $reader)
    {
    }

    public function parse() : File
    {
        $obj = new File();

        if ($this->reader->length() < 12) {
            throw new InvalidWadException('File too small to be a valid WAD.');
        }

        $type = $this->reader->read(4);
        if ($type !== 'IWAD' && $type !== 'PWAD') {
            throw new InvalidWadException("Invalid WAD type: {$type}");
        }

        $lumpCount = $this->reader->readUInt32LE();
        $directoryOffset = $this->reader->readUInt32LE();

        $obj->header = new Header($type, $lumpCount, $directoryOffset);

        $directorySize = $lumpCount * 16;
        if ($directoryOffset + $directorySize > $this->reader->length()) {
            throw new OutOfBoundsException('Directory exceeds file bounds.');
        }

        $this->reader->seek($directoryOffset);

        for ($i = 0; $i < $lumpCount; $i++) {
            $lumpOffset = $this->reader->readUInt32LE();
            $lumpSize = $this->reader->readUInt32LE();

            $rawName = $this->reader->read(8);
            $name = strtoupper(rtrim($rawName, "\0 "));

            if ($lumpSize < 0) {
                throw new InvalidWadException("Invalid lump size at index {$i}.");
            }

            if ($lumpSize === 0) {
                $data = '';
            } else {
                $pos = $this->reader->tell();
                $this->reader->seek($lumpOffset);
                $data = $this->reader->read($lumpSize);
                $this->reader->seek($pos);
            }

            $obj->lumps[] = new Lump(
                offset: $lumpOffset,
                size: $lumpSize,
                name: $name,
                data: $data,
                index: $i,
            );
        }
        return $obj;
    }
}
