<?php

declare(strict_types=1);

namespace Seka\Portal\Modul\Statistiky\Services\Transformators;

use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Worksheet\RowIterator;
use Seka\Portal\Modul\Statistiky\Entities\Zaznam\DTOs\ImportLineDTO;
use Seka\Portal\Modul\Statistiky\Services\Import\File;

/**
 * Class XLSXDataTransformator
 *
 * @package Seka\Portal\Modul\Statistiky\Services\Transformators
 */
class XLSXDataTransformator implements DataTransformatorContract
{
    /**
     * @inheritDoc
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     */
    public function transform(File $file): array
    {
        $reader = IOFactory::createReader(IOFactory::READER_XLSX);
        $reader->setReadDataOnly(TRUE);
        $spreadsheet = $reader->load($file->fileName());
        $spreadsheet->garbageCollect();
        $worksheet = $spreadsheet->getActiveSheet();
        $worksheet->garbageCollect();
        $rowIterator = $worksheet->getRowIterator();
        $objects = $this->mapDataToObjects($rowIterator);

        $spreadsheet->disconnectWorksheets();
        unset($rowIterator, $worksheet, $spreadsheet, $reader);

        return $objects;
    }

    /**
     * Open XML (XLSX) ma datumove polia ulozene v ciselnej podobe, je potrebne ich preformatovat na datum
     *
     * @param string $format
     * @param float  $dateNum
     *
     * @return string
     */
    public static function convertIntToDate(string $format, float $dateNum): string
    {
        return NumberFormat::toFormattedString($dateNum, $format);
    }

    /**
     * @param \PhpOffice\PhpSpreadsheet\Worksheet\RowIterator $rowIterator
     *
     * @return array
     */
    private function mapDataToObjects(RowIterator $rowIterator): array
    {
        $out = [];
        $keys = [];

        foreach ($rowIterator as $row) {
            $mappedRow = [];

            if ($row->getRowIndex() == 1) {
                foreach ($row->getCellIterator() as $cell) {
                    $keys[] = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $cell->getValue()))));
                }

                continue;
            }

            $cellIdx = 0;
            foreach ($row->getCellIterator() as $cell) {
                $mappedRow[$keys[$cellIdx]] = $cell->getValue() ?? '';
                ++$cellIdx;
            }

            $mappedRow['kontrolaDatum'] = $this->convertIntToDate('DD.MM.YYYY', $mappedRow['kontrolaDatum']);
            $out[] = ImportLineDTO::from($mappedRow);
        }

        return $out;
    }
}
