<?php

declare(strict_types=1);

namespace Seka\Portal\Modul\Statistiky\Entities\Zaznam\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use InvalidArgumentException;
use Seka\Portal\Modul\Statistiky\Entities\Zaznam\Enums\DruhSubjektuZaznamuEnum;
use Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\Udaje as UdajeContract;
use Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\UdajePreTypZaznamuPouzivatel;
use Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\UdajePreTypZaznamuPracovisko;
use Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\ZoznamPoctuKontrolAObratuPodlaSubjektuFakturacie;
use Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\ZoznamPoctuKontrolPodlaDruhu;
use Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\ZoznamPoctuKontrolPodlaDruhuAHodnotenia;
use Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\ZoznamPoctuKontrolPodlaDruhuPalivaAEmisnehoSystemuVozidla;
use Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\ZoznamPoctuKontrolPodlaHodnotenia;
use Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\ZoznamPoctuKontrolPodlaKategorieVozidla;
use Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\ZoznamPoctuKontrolPodlaStavu;
use Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\ZoznamPoctuKontrolSObratom;
use Seka\Portal\Modul\Statistiky\Exceptions\NeznamiDruhZaznamuException;

/**
 * Class UdajeCast
 *
 * @package Seka\Portal\Modul\Statistiky\Entities\Zaznam\Casts
 */
final class UdajeCast implements CastsAttributes
{
    /**
     * @param \Seka\Portal\Modul\Statistiky\Entities\Zaznam\Zaznam $model
     * @param string                                               $key
     * @param mixed                                                $value
     * @param array                                                $attributes
     *
     * @return \Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\Udaje
     * @throws \Seka\Portal\Modul\Statistiky\Exceptions\NeznamiDruhZaznamuException
     */
    public function get($model, string $key, $value, array $attributes): UdajeContract
    {
        if (!is_string($value)) {
            $value = '{}';
        }

        $val = json_decode($value, true);

        return match (DruhSubjektuZaznamuEnum::from($attributes['subjekt_druh'])) {
            DruhSubjektuZaznamuEnum::POUZIVATEL => $this->createObjectUdajePouzivatela($val),
            DruhSubjektuZaznamuEnum::PRACOVISKO => $this->createObjectUdajePracoviska($val),
            default => throw new NeznamiDruhZaznamuException(
                sprintf('Neznama hodnota (%s) pre druh zaznamu.', $model->subjekt_druh)
            ),
        };
    }

    /**
     * @param array $values
     *
     * @return \Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\UdajePreTypZaznamuPouzivatel
     */
    private function createObjectUdajePouzivatela(array $values): UdajePreTypZaznamuPouzivatel
    {
        return new UdajePreTypZaznamuPouzivatel(
            ZoznamPoctuKontrolSObratom::createFromArray($values['zoznamPoctuKontrolSObratom'] ?? []),
            ZoznamPoctuKontrolPodlaDruhu::createFromArray($values['zoznamPoctuKontrolPodlaDruhu'] ?? []),
            ZoznamPoctuKontrolPodlaStavu::createFromArray($values['zoznamPoctuKontrolPodlaStavu'] ?? []),
            ZoznamPoctuKontrolPodlaHodnotenia::createFromArray($values['zoznamPoctuKontrolPodlaHodnotenia'] ?? []),
            ZoznamPoctuKontrolPodlaKategorieVozidla::createFromArray($values['zoznamPoctuKontrolPodlaKategorieVozidla'] ?? []),
            ZoznamPoctuKontrolPodlaDruhuPalivaAEmisnehoSystemuVozidla::createFromArray($values['zoznamPoctuKontrolPodlaDruhuPalivaAEmisnehoSystemuVozidla'] ?? [])
        );
    }

    /**
     * @param array $values
     *
     * @return \Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\UdajePreTypZaznamuPracovisko
     */
    private function createObjectUdajePracoviska(array $values): UdajePreTypZaznamuPracovisko
    {
        return new UdajePreTypZaznamuPracovisko(
            ZoznamPoctuKontrolPodlaDruhuAHodnotenia::createFromArray($values['zoznamPoctuKontrolPodlaDruhuAHodnotenia'] ?? []),
            ZoznamPoctuKontrolPodlaKategorieVozidla::createFromArray($values['zoznamPoctuKontrolPodlaKategorieVozidla'] ?? []),
            ZoznamPoctuKontrolPodlaDruhuPalivaAEmisnehoSystemuVozidla::createFromArray($values['zoznamPoctuKontrolPodlaDruhuPalivaAEmisnehoSystemuVozidla'] ?? []),
            ZoznamPoctuKontrolAObratuPodlaSubjektuFakturacie::createFromArray($values['zoznamPoctuKontrolAObratuPodlaSubjektuFakturacie'] ?? []),
            ZoznamPoctuKontrolPodlaStavu::createFromArray($values['zoznamPoctuKontrolPodlaStavu'] ?? [])
        );
    }

    /**
     * @param \Seka\Portal\Modul\Statistiky\Entities\Zaznam\Zaznam $model
     * @param string                                               $key
     * @param mixed                                                $value
     * @param array                                                $attributes
     *
     * @return string
     * @throws \Seka\Portal\Modul\Statistiky\Exceptions\NeznamiDruhZaznamuException
     */
    public function set($model, string $key, $value, array $attributes): string
    {
        if ((!$value instanceof UdajePreTypZaznamuPouzivatel) && (!$value instanceof UdajePreTypZaznamuPracovisko)) {
            throw new InvalidArgumentException(
                sprintf('Hodnota nie je instanciou triedy %s', UdajeContract::class)
            );
        }

        return match (DruhSubjektuZaznamuEnum::from($attributes['subjekt_druh'])) {
            DruhSubjektuZaznamuEnum::POUZIVATEL => $this->createJsonUdajePouzivatela($value),
            DruhSubjektuZaznamuEnum::PRACOVISKO => $this->createJsonUdajePracoviska($value),
            default => throw new NeznamiDruhZaznamuException(
                sprintf('Neznama hodnota (%s) pre druh zaznamu.', $model->subjekt_druh)
            ),
        };
    }

    /**
     * @param \Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\UdajePreTypZaznamuPouzivatel $udaje
     *
     * @return string
     */
    private function createJsonUdajePouzivatela(UdajePreTypZaznamuPouzivatel $udaje): string
    {
        return json_encode([
            'zoznamPoctuKontrolSObratom' => $udaje->zoznamPoctuKontrolSObratom()->toArray(),
            'zoznamPoctuKontrolPodlaDruhu' => $udaje->zoznamPoctuKontrolPodlaDruhu()->toArray(),
            'zoznamPoctuKontrolPodlaStavu' => $udaje->zoznamPoctuKontrolPodlaStavu()->toArray(),
            'zoznamPoctuKontrolPodlaHodnotenia' => $udaje->zoznamPoctuKontrolPodlaHodnotenia()->toArray(),
            'zoznamPoctuKontrolPodlaKategorieVozidla' => $udaje->zoznamPoctuKontrolPodlaKategorieVozidla()->toArray(),
            'zoznamPoctuKontrolPodlaDruhuPalivaAEmisnehoSystemuVozidla' => $udaje->zoznamPoctuKontrolPodlaDruhuPalivaAEmisnehoSystemuVozidla()->toArray(),
        ]);
    }

    /**
     * @param \Seka\Portal\Modul\Statistiky\Entities\Zaznam\ValueObjects\UdajePreTypZaznamuPracovisko $udaje
     *
     * @return string
     */
    private function createJsonUdajePracoviska(UdajePreTypZaznamuPracovisko $udaje): string
    {
        return json_encode([
            'zoznamPoctuKontrolPodlaStavu' => $udaje->zoznamPoctuKontrolPodlaStavu()->toArray(),
            'zoznamPoctuKontrolPodlaDruhuAHodnotenia' => $udaje->zoznamPoctuKontrolPodlaDruhuAHodnotenia()->toArray(),
            'zoznamPoctuKontrolPodlaKategorieVozidla' => $udaje->zoznamPoctuKontrolPodlaKategorieVozidla()->toArray(),
            'zoznamPoctuKontrolAObratuPodlaSubjektuFakturacie' => $udaje->zoznamPoctuKontrolAObratuPodlaSubjektuFakturacie() ? $udaje->zoznamPoctuKontrolAObratuPodlaSubjektuFakturacie()->toArray() : null,
            'zoznamPoctuKontrolPodlaDruhuPalivaAEmisnehoSystemuVozidla' => $udaje->zoznamPoctuKontrolPodlaDruhuPalivaAEmisnehoSystemuVozidla()->toArray(),
        ]);
    }
}
