<?php

namespace Doom\Wad;

use Doom\Picture\Picture;
use Doom\Texture\ResolvedTexture;
use Doom\Texture\TextureX;
use Doom\Texture\TextureResolver;
use Doom\Wad\Types\Header;
use Doom\Wad\Types\Lump;
use Illuminate\Support\Collection;
use OutOfBoundsException;
use Shufflingpixels\IO\BinaryReader;

final class File
{
    public Header $header;

    /** @var Collection<Lump> */
    public Collection $lumps;

    public function __construct()
    {
        $this->lumps = new Collection();
    }

    public function header(): Header
    {
        return $this->header;
    }

    /**
     * @return Collection<Lump>
     */
    public function lumps(): Collection
    {
        return $this->lumps;
    }

    public function lump(int $index): Lump
    {
        if (!isset($this->lumps[$index])) {
            throw new OutOfBoundsException("Lump index {$index} does not exist.");
        }

        return $this->lumps[$index];
    }

    public function firstLumpByName(string $name): ?Lump
    {
        $name = strtoupper($name);
        return $this->lumps->first(fn (Lump $item) => $item->name === $name);
    }

    /**
     * @return Collection<Lump>
     */
    public function lumpsByName(string $name): Collection
    {
        $name = strtoupper($name);

        return $this->lumps->filter(fn (Lump $item) => $item->name === $name);
    }

    public function firstPictureByName(string $name): ?Picture
    {
        return $this->firstLumpByName($name)?->asPicture();
    }

    public function firstTextureXByName(string $name): ?TextureX
    {
        return $this->firstLumpByName($name)?->asTextureX();
    }

    /**
     * @return string[]|null
     */
    public function pNames(): ?array
    {
        return $this->firstLumpByName('PNAMES')?->asPNames();
    }

    /**
     * @param string[] $textureLumpNames
     * @return array<string, ResolvedTexture>
     */
    public function resolveTextures(array $textureLumpNames = ['TEXTURE1', 'TEXTURE2']): array
    {
        return TextureResolver::forWad($this)->resolveAll($textureLumpNames);
    }

    public static function parse(BinaryReader $reader): self
    {
        return (new Parser($reader))->parse();
    }
}
