<?php

namespace Lightscale\LaralightSvg;

use Illuminate\Support\Facades\Storage;

class SvgCollection
{
    protected array $paths;
    protected int $maxAge;

    private ?SvgCollectionState $state = null;

    public function __construct(
        private readonly string $name,
        array $config = [],
    )
    {
        $this->paths = $config['paths'] ?? [];
        $this->maxAge = $config['max_age'] ?? config('svg.default_max_age', 0);
    }

    public function addPath(string $path)
    {
        $this->paths[] = $path;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function getSvgUrl(string $svg): string
    {
        $state = $this->getState();
        $state->addSvg($svg);
        $hash = $state->getHash();
        return route(
            'laralight-svg.serve-svg',
            ['collection' => $this->getName(), 'v' => $hash]
        ) . "#{$svg}";
    }

    protected function getState(): SvgCollectionState
    {
        if ($this->state === null) {
            $this->state = new SvgCollectionState($this->getName());
        }
        return $this->state;
    }

    public function getSvg(): ?string
    {
        $state = $this->getState();
        if ($state->hasPending()) {
            $this->compileSvg();
        }
        return $state->getFullSvg();
    }

    protected function compileSvg(): void
    {
        $state = $this->getState();
        $svg = $state->getFullSvg();
        $compiler = new SvgSpriteCompiler($svg);

        if ($compiler->isNew()) {
            $state->clearExisting(false);
        }

        $pending = $state->getPending();
        $added = [];
        $disks = array_map(
            fn($p) => Storage::build(['driver' => 'local', 'root' => $p]),
            array_reverse($this->paths)
        );

        foreach ($pending as $pendingSvg) {
            $file = $this->getFile($disks, $pendingSvg);
            if ($file !== null && $compiler->addSvg($pendingSvg, $file)) {
                $added[] = $pendingSvg;
            }
            else {
                \Log::error("Failed to add {$pendingSvg} to svg sprite");
            }
        }

        $state->clearPending(false);
        $state->concatExisting($added, false);
        $state->setFullSvg($compiler->getSvg(), false);
        $state->updateHash();
        $state->push();
    }

    protected function getFile(array $disks, string $svg): ?string
    {
        foreach ($disks as $disk) {
            $file = $disk->get("{$svg}.svg");
            if ($file !== null) return $file;
        }
        return null;
    }

    public function clearState(): void
    {
        $this->getState()->clear();
    }

    public function getMaxAge(): int
    {
        return $this->maxAge;
    }

}