<?php
declare(strict_types=1);

namespace Autogedal\EanTools\Model\Spreadsheet;

use Magento\Framework\Exception\LocalizedException;
use OpenSpout\Common\Entity\Cell;
use OpenSpout\Common\Entity\Cell\EmptyCell;
use OpenSpout\Common\Entity\Cell\NumericCell;
use OpenSpout\Common\Entity\Cell\StringCell;
use OpenSpout\Common\Entity\Row;
use OpenSpout\Common\Entity\Style\Style;
use OpenSpout\Writer\XLSX\Options;
use OpenSpout\Writer\XLSX\Writer;
use Throwable;

class XlsxRowWriter implements RowWriterInterface
{
    private readonly Writer $writer;

    public function __construct(
        TempFolder $tempFolder,
        string $absolutePath,
        array $header
    ) {
        $options = new Options();
        $options->SHOULD_USE_INLINE_STRINGS = true;
        $options->setTempFolder($tempFolder->getPath());

        $this->writer = new Writer($options);

        try {
            $this->writer->openToFile($absolutePath);
            $this->writer->addRow($this->buildRow($header, [], $this->buildHeaderStyle()));
        } catch (Throwable $e) {
            $this->closeSilently();
            $fileName = strrchr(str_replace('\\', '/', $absolutePath), '/');
            $fileName = $fileName === false ? $absolutePath : substr($fileName, 1);

            throw new LocalizedException(
                __(
                    'The output file "%1" could not be created: %2',
                    $fileName,
                    $e->getMessage()
                )
            );
        }
    }

    public function __destruct()
    {
        $this->closeSilently();
    }

    public function writeRow(array $row, array $textColumns = []): void
    {
        $this->writer->addRow($this->buildRow($row, $textColumns));
    }

    public function close(): void
    {
        $this->writer->close();
    }

    private function buildRow(array $values, array $textColumns, ?Style $style = null): Row
    {
        $forceText = array_flip($textColumns);
        $cells = [];
        $index = 0;

        foreach ($values as $value) {
            $cells[] = isset($forceText[$index])
                ? new StringCell((string)$value, $style)
                : $this->buildCell($value, $style);
            $index++;
        }

        return new Row($cells, $style);
    }

    private function buildCell(mixed $value, ?Style $style): Cell
    {
        if ($value === null || $value === '') {
            return new EmptyCell(null, $style);
        }

        if (is_bool($value)) {
            return new StringCell($value ? '1' : '0', $style);
        }

        if (is_int($value) || is_float($value)) {
            return new NumericCell($value, $style);
        }

        return new StringCell((string)$value, $style);
    }

    private function buildHeaderStyle(): Style
    {
        $style = new Style();
        $style->setFontBold();

        return $style;
    }

    private function closeSilently(): void
    {
        try {
            $this->writer->close();
        } catch (Throwable) {
            return;
        }
    }
}
