<?php

declare(strict_types=1);

namespace Seka\Vzdelavanie\Commands\Console;

use Exception;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use PhpOffice\PhpSpreadsheet\IOFactory;
use Illuminate\Database\Eloquent\Builder;
use PhpOffice\PhpSpreadsheet\Worksheet\Row;
use Seka\Vzdelavanie\Enums\ModelStatusEnum;
use Seka\Vzdelavanie\Models\Testovanie\Test;
use Seka\Vzdelavanie\Models\Testovanie\Otazka;
use Seka\Vzdelavanie\Models\Testovanie\Odpoved;
use Seka\Vzdelavanie\Models\Testovanie\HodnotenieOdpovedeEnum;
use Seka\Vzdelavanie\Models\Testovanie\DruhSpravnejOdpovedeEnum;

/**
 * Class ImportTestov
 *
 * @package Seka\Vzdelavanie\Commands\Console
 */
final class ImportTestov extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'import:testy {subor}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Import otazok a odpovedi testov';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     *
     */
    public function handle()
    {
        try {
            $subor = sprintf('%s%s%s', base_path(), DIRECTORY_SEPARATOR, $this->argument('subor'));
            $reader = IOFactory::load($subor);
            $nazvyZositov = $reader->getSheetNames();
            $nazvyZositov = $this->vratMultidimenzionalnePole($nazvyZositov);

            $this->output->title('Zoznam zositov (typov testov):');
            $this->output->table(['Nazov'], $nazvyZositov);

            DB::beginTransaction();

            // zneplatnenie existujucich testov
            Test::query()->where('stav', ModelStatusEnum::PUBLIKOVANE())->take(5)->each(function (Test $test) {
                $test
                    ->setAttribute('stav', ModelStatusEnum::NEPUBLIKOVANE())
                    ->setAttribute('popis', $test->popis . PHP_EOL . PHP_EOL . 'Zneplatnený pri importe nových testov ' . date('d.m.Y H:i:s'))
                    ->save();
            });

            foreach ($reader->getWorksheetIterator() as $sheet) {
                /**
                 * Ak nie je zosit zobrazeny, tak sa nespracuje
                 * @var \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet
                 */
                if ($sheet->getSheetState() !== $sheet::SHEETSTATE_VISIBLE) continue;

                $test = new Test();
                $test->setAttribute('nazov', ucfirst($sheet->getTitle()));
                $test->setAttribute('popis', 'Test obsahuje otázky a odpovede kategórie ' . $sheet->getTitle());
                $test->setAttribute('stav', ModelStatusEnum::PUBLIKOVANE());
                $test->save();
                $test = $test->fresh();

                foreach ($sheet->getRowIterator() as $row) {
                    if ($row->getRowIndex() == 1) {
                        continue;
                    }

                    $this->importOtazokAOdpovedi($test, $row);
                }

                $pocetZverejnenychOtazokTestu = $test->otazky()->where(function (Builder $query) {
                    $query->where('stav', ModelStatusEnum::PUBLIKOVANE());
                })->count();

                $test->setAttribute('pocet_otazok', (int) ($pocetZverejnenychOtazokTestu / 2));
                $test->save();

                $test->refresh();

                // ak test nema publikovane ziadne otazky, tak on sam nebude publikovany
                if ($test->otazky()->publikovana()->count() <= 0) {
                    $test->setAttribute('stav', ModelStatusEnum::NEPUBLIKOVANE());
                    $test->save();
                }
            }

            DB::commit();
        } catch (Exception $e) {
            DB::rollBack();

            $this->output->error($e->getMessage());
        }
    }

    /**
     * @param \Seka\Vzdelavanie\Models\Testovanie\Test $test
     * @param \PhpOffice\PhpSpreadsheet\Worksheet\Row  $row
     *
     * @return void
     */
    private function importOtazokAOdpovedi(Test $test, Row $row): void
    {
        /** @var Otazka $otazka */
        $otazka = null;
        /** @var Odpoved $odpoved */
        $odpoved = null;

        // iteracia stlpcov v riadku
        foreach ($row->getCellIterator() as $cell) {
            if ($cell->getColumn() === 'A') {
                continue;
            }

            if ($this->jeStavOtazky($cell->getColumn())) {
                $otazka = new Otazka();
                $otazka->setAttribute(
                    'stav',
                    $this->vratBoolean($cell->getValue()) ? ModelStatusEnum::PUBLIKOVANE() : ModelStatusEnum::NEPUBLIKOVANE()
                );
            }

            if (is_null($cell->getValue())) {
                continue;
            }

            if ($this->jeOtazka($cell->getColumn())) {
                $otazka->setAttribute('znenie', $cell->getValue());
                $otazka->setAttribute('druh_spravnej_odpovede', DruhSpravnejOdpovedeEnum::JEDNA());
                $test->otazky()->save($otazka);

                continue;
            }

            if ($this->jeOdpoved($cell->getColumn())) {
                $odpoved = (new Odpoved())->fill([
                    'znenie' => $cell->getValue(),
                    'stav' => ModelStatusEnum::PUBLIKOVANE(),
                ]);

                continue;
            }

            if ($this->jeHodnotenie($cell->getColumn())) {
                $odpoved->setAttribute(
                    'hodnotenie',
                    ((bool) $cell->getValue()) ? HodnotenieOdpovedeEnum::SPRAVNA() : HodnotenieOdpovedeEnum::NESPRAVNA()
                );
                $otazka->odpovede()->save($odpoved);

                continue;
            }
        }
    }

    /**
     * @param string $stlpec
     *
     * @return bool
     */
    private function jeStavOtazky(string $stlpec): bool
    {
        $stavOtazky = ['B'];

        return in_array($stlpec, $stavOtazky);
    }

    /**
     * @param string $stlpec
     * @return bool
     */
    private function jeOtazka(string $stlpec): bool
    {
        $otazka = ['C'];

        return in_array($stlpec, $otazka);
    }

    /**
     * @param string $stlpec
     * @return bool
     */
    private function jeOdpoved(string $stlpec): bool
    {
        $znenieOdpovede = ['D', 'F', 'H', 'J', 'L', 'N', 'P', 'R', 'T'];

        return in_array($stlpec, $znenieOdpovede);
    }

    /**
     * @param string $stlpec
     * @return bool
     */
    private function jeHodnotenie(string $stlpec): bool
    {
        $hodnotenieOdpovede = ['E', 'G', 'I', 'K', 'M', 'O', 'Q', 'S', 'U'];

        return in_array($stlpec, $hodnotenieOdpovede);
    }

    /**
     * @param array $pole
     * @return array
     */
    private function vratMultidimenzionalnePole(array $pole)
    {
        $polozky = [];

        foreach ($pole as $polozka) {
            $polozky[] = [$polozka];
        }

        return $polozky;
    }

    /**
     * @param $hodnota
     *
     * @return bool
     */
    private function vratBoolean($hodnota): bool
    {
        if (is_bool($hodnota)) {
            return $hodnota;
        }

        if (is_string($hodnota)) {
            return strcasecmp($hodnota, 'TRUE') === 0;
        }

        return false;
    }
}
