<?php

declare(strict_types=1);

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

use App\Repositories\PracoviskoRepositoryContract;
use LogicException;
use Seka\Portal\Modul\Statistiky\Facades\ZaznamFactory;
use Seka\Portal\Modul\Statistiky\Repositories\ZaznamRepositoryContract;
use Seka\Portal\Modul\Statistiky\Services\Analyzators\DataAnalyzatorContract;
use Seka\Portal\Modul\Statistiky\Services\Processors\ProcessDataPEK;
use Seka\Portal\Modul\Statistiky\Services\Processors\ProcessDataTEK;
use Seka\Portal\Modul\Statistiky\Services\Transformators\DataTransformatorContract;

/**
 * Class ImportDataService
 *
 * @package Seka\Portal\Modul\Statistiky\Services\Import
 */
final class ImportDataService implements ImportDataServiceContract
{
    /**
     * @var \Seka\Portal\Modul\Statistiky\Services\Analyzators\DataAnalyzatorContract
     */
    private DataAnalyzatorContract $importDataAnalyzator;
    /**
     * @var \Seka\Portal\Modul\Statistiky\Services\Transformators\DataTransformatorContract
     */
    private DataTransformatorContract $dataTransformator;
    /**
     * @var \Seka\Portal\Modul\Statistiky\Repositories\ZaznamRepositoryContract
     */
    private ZaznamRepositoryContract $zaznamRepository;
    /**
     * @var \App\Repositories\PracoviskoRepositoryContract
     */
    private PracoviskoRepositoryContract $pracoviskoRepository;

    /**
     * ImportDataService constructor.
     *
     * @param \Seka\Portal\Modul\Statistiky\Repositories\ZaznamRepositoryContract             $zaznamRepository
     * @param \Seka\Portal\Modul\Statistiky\Services\Analyzators\DataAnalyzatorContract       $importDataAnalyzator
     * @param \App\Repositories\PracoviskoRepositoryContract                                  $pracoviskoRepository
     * @param \Seka\Portal\Modul\Statistiky\Services\Transformators\DataTransformatorContract $importDataTransformation
     */
    public function __construct(
        ZaznamRepositoryContract     $zaznamRepository,
        DataAnalyzatorContract       $importDataAnalyzator,
        PracoviskoRepositoryContract $pracoviskoRepository,
        DataTransformatorContract    $importDataTransformation
    )
    {
        $this->zaznamRepository = $zaznamRepository;
        $this->importDataAnalyzator = $importDataAnalyzator;
        $this->pracoviskoRepository = $pracoviskoRepository;
        $this->dataTransformator = $importDataTransformation;
    }

    /**
     * @param \Seka\Portal\Modul\Statistiky\Services\Import\File $file
     *
     * @throws \Seka\Portal\Modul\Statistiky\Exceptions\NeznamiDruhZaznamuException
     * @throws \Throwable
     */
    public function execute(File $file): void
    {
        $file->check();

        if (false === $this->importDataAnalyzator->analyze(DataAnalyzatorContract::LEXICAL, $file)) {
            throw new LogicException('Subor nevyhovuje analyze.' . "\n" . implode('\n', $this->importDataAnalyzator->getErrors()));
        }

        /** @var \Seka\Portal\Modul\Statistiky\Entities\Zaznam\DTOs\ImportLineDTO[] $transformedData */
        $transformedData = $this->dataTransformator->transform($file);

        $dataPEK = ProcessDataPEK::process($transformedData);
        $this->storeData($dataPEK);
        unset($dataPEK);
        $dataTEK = ProcessDataTEK::process($transformedData);
        unset($transformedData);
        $this->storeData($dataTEK);
        unset($dataTEK);
    }

    /**
     * @param \Seka\Portal\Modul\Statistiky\Entities\Zaznam\DTOs\ZaznamDTO[] $records
     *
     * @return void
     * @throws \Seka\Portal\Modul\Statistiky\Exceptions\NeznamiDruhZaznamuException
     * @throws \Throwable
     */
    protected function storeData(array $records): void
    {
        foreach ($records as $item) {
            $pek = $this->pracoviskoRepository->findByField('kod', $item->kodPracoviska)->first();

            if (is_null($pek)) continue;

            $zaznam = ZaznamFactory::make($item);
            $zaznam = $zaznam->pracovisko()->associate($pek);
            $this->zaznamRepository->createOrUpdateFromEntity($zaznam);

            unset($pek, $zaznam);
        }
    }
}
