<?php

namespace Myvetshop\Module\Clinique\Import\Kalivet\ImportFile;

/**
 * @implements \Iterator<int, array<string, string|int|float|null>>
 */
class ImportFileParser implements \Iterator
{
    /**
     * @var resource
     */
    private $stream;

    private ?string $section = null;

    private int $i = 0;

    /**
     * @var array<string, string|int|float|null>|null
     */
    private ?array $datum = null;

    private function readLine(): ?string
    {
        $line = \fgets($this->stream, 16384);

        return false === $line ? null : $line;
    }

    private function parseSection(string $row): ?string
    {
        if (\str_starts_with($row, '### ')) {
            return \substr($row, 4);
        }

        return null;
    }

    /**
     * @param resource $stream
     */
    public function __construct($stream)
    {
        $this->stream = $stream;
    }

    public function current(): mixed
    {
        \assert(\is_array($this->datum));

        return $this->datum;
    }

    public function next(): void
    {
        $this->datum = null;

        $ct = 0;

        while (null === $this->datum && null !== ($line = $this->readLine())) {
            ++$ct;
            ++$this->i;

            $section = $this->parseSection($line);
            if (null !== $section) {
                $this->section = \trim($section);
                continue;
            }

            $datum = \json_decode($line, true);
            if (!\is_array($datum)) {
                if (!empty(\trim($line))) {
                    throw new \Exception($line);
                } else {
                    continue;
                }
            }

            $this->datum = $datum;
        }
    }

    public function key(): int
    {
        return $this->i;
    }

    public function valid(): bool
    {
        return null !== $this->section && null !== $this->datum;
    }

    public function rewind(): void
    {
        \rewind($this->stream);
        $this->section = null;
        $this->datum = null;
        $this->i = 0;

        $this->next();
    }

    /**
     * @return string|null
     */
    public function getSection(): ?string
    {
        return $this->section;
    }
}
