<?php
/**
 * Generates collision-free Bricks element IDs.
 *
 * @package LolaCoreForBricks
 */

declare(strict_types=1);

namespace LolaCoreForBricks\Elements;

/**
 * Bricks IDs are 6 lowercase hex characters (Helpers::generate_hash).
 */
final class IdGenerator
{
    public const LENGTH = 6;

    /**
     * @param string[] $existingIds
     */
    public function generate(array $existingIds): string
    {
        $taken = [];
        foreach ($existingIds as $id) {
            $taken[(string) $id] = true;
        }

        for ($attempt = 0; $attempt < 32; $attempt++) {
            $id = $this->randomId();
            if (!isset($taken[$id])) {
                return $id;
            }
        }

        $suffix = 0;
        do {
            $id = substr(hash('sha1', $this->randomId() . (string) $suffix), 0, self::LENGTH);
            ++$suffix;
        } while (isset($taken[$id]));

        return $id;
    }

    /**
     * @param string[] $existingIds
     * @return array<string, string> oldId => newId
     */
    public function remap(array $oldIds, array $existingIds): array
    {
        $taken = $existingIds;
        $map   = [];

        foreach ($oldIds as $oldId) {
            $oldId = (string) $oldId;
            if ($oldId === '' || isset($map[$oldId])) {
                continue;
            }

            $newId         = $this->generate($taken);
            $map[$oldId]   = $newId;
            $taken[]       = $newId;
        }

        return $map;
    }

    public static function isValid(string $id): bool
    {
        return (bool) preg_match('/^[a-f0-9]{' . self::LENGTH . '}$/', $id);
    }

    private function randomId(): string
    {
        return bin2hex(random_bytes(3));
    }
}
