<?php

namespace Tests\Unit\App\Models\Informacia;

use App\Models\Informacia\Enums\StavInformacieEnum;
use App\Models\Informacia\Informacia;
use App\Models\Pouzivatel\Pouzivatel;
use App\Models\Pracovisko\Pracovisko;
use Database\Seeders\PortalPouzivatelRoleOpravneniaDatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Event;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;

final class InformaciaTest extends TestCase
{
    use RefreshDatabase;

    #[Test]
    public function it_can_create_an_informacia(): void
    {
        /** @var Pracovisko $pek */
        $pek = Pracovisko::factory()->create();
        /** @var Pouzivatel $pouzivatel */
        $pouzivatel = Pouzivatel::factory()
            ->make()
            ->pracovisko()
            ->associate($pek);
        $pouzivatel->save();
        $pouzivatel->refresh();

        $informaciaData = [
            'titulok' => 'Testovací titulok',
            'obsah' => 'Toto je testovací obsah.',
            'stav' => collect(StavInformacieEnum::cases())->random(1)->first(),
            'zverejnit_pre_pouzivatelov_podla_role' => ['admin', 'editor'],
            'planovany_cas_zverejnenia' => now()->addDays(rand(1, 30)),
            'odoslat_email_pouzivatelom' => boolval(rand(0, 1)),
            'odoslat_push_notifikacie_pouzivatelom' => boolval(rand(0, 1)),
            'cas_zverejnenia' => rand(0, 1) ? now()->addDays(rand(30, 35)) : null,
            'odporucane' => boolval(rand(0, 1)),
        ];

        $informacia = Informacia::factory()
            ->make($informaciaData)
            ->vytvoril()
            ->associate($pouzivatel);
        $informacia->save();
        $informacia->refresh();

        $this->assertNotNull($informacia->id);
        $this->assertEquals($informacia->vytvoril_id, $informacia->vytvoril_id);
        $this->assertEquals($informaciaData['titulok'], $informacia->titulok);
        $this->assertEquals($informaciaData['obsah'], $informacia->obsah);
        $this->assertEquals($informaciaData['stav'], $informacia->stav);
        $this->assertEquals(
            $informaciaData['zverejnit_pre_pouzivatelov_podla_role'],
            $informacia->zverejnit_pre_pouzivatelov_podla_role,
        );
        $this->assertEquals(
            $informaciaData['planovany_cas_zverejnenia']->toDateTimeString(),
            $informacia->planovany_cas_zverejnenia->toDateTimeString(),
        );
        $this->assertEquals($informaciaData['odoslat_email_pouzivatelom'], $informacia->odoslat_email_pouzivatelom);
        $this->assertEquals(
            $informaciaData['odoslat_push_notifikacie_pouzivatelom'],
            $informacia->odoslat_push_notifikacie_pouzivatelom,
        );
        $this->assertEquals($informaciaData['odporucane'], $informacia->odporucane);

        if (is_null($informaciaData['cas_zverejnenia'])) {
            $this->assertNull($informaciaData['cas_zverejnenia']);
        } else {
            $this->assertEquals(
                $informaciaData['cas_zverejnenia']->toDateTimeString(),
                $informacia->cas_zverejnenia->toDateTimeString(),
            );
        }
    }

    #[Test]
    public function it_belongs_to_a_pouzivatel(): void
    {
        /** @var Pracovisko $pek */
        $pek = Pracovisko::factory()->create();
        /** @var Pouzivatel $user */
        $pouzivatel = Pouzivatel::factory()
            ->make()
            ->pracovisko()
            ->associate($pek);
        $pouzivatel->save();
        $pouzivatel->refresh();
        $informacia = Informacia::factory()
            ->make()
            ->vytvoril()
            ->associate($pouzivatel);
        $informacia->save();
        $informacia->refresh();

        $this->assertInstanceOf(Pouzivatel::class, $informacia->vytvoril);
        $this->assertEquals($pouzivatel->id, $informacia->vytvoril->id);
    }

    #[Test]
    public function it_stores_zverejnit_pre_pouzivatelov_podla_role_as_json(): void
    {
        $this->seed(PortalPouzivatelRoleOpravneniaDatabaseSeeder::class);

        $roles = ['admin', 'spravca_pek'];
        /** @var Pracovisko $pek */
        $pek = Pracovisko::factory()->create();
        /** @var Pouzivatel $user */
        $pouzivatel = Pouzivatel::factory()
            ->make()
            ->pracovisko()
            ->associate($pek)
            ->assignRole($roles);
        $pouzivatel->save();
        $pouzivatel->refresh();
        $informacia = Informacia::factory()
            ->make([
                'zverejnit_pre_pouzivatelov_podla_role' => $roles,
            ])
            ->vytvoril()
            ->associate($pouzivatel);
        $informacia->save();
        $informacia->refresh();

        $this->assertEquals($roles, $informacia->zverejnit_pre_pouzivatelov_podla_role);
        $this->assertDatabaseHas('informacie', [
            'id' => $informacia->id,
        ]);
        $this->assertJsonStringEqualsJsonString(
            json_encode($roles),
            json_encode($informacia->zverejnit_pre_pouzivatelov_podla_role),
        );
    }

    #[Test]
    public function it_can_retrieve_all_attributes(): void
    {
        /** @var Pracovisko $pek */
        $pek = Pracovisko::factory()->create();
        /** @var Pouzivatel $user */
        $pouzivatel = Pouzivatel::factory()
            ->make()
            ->pracovisko()
            ->associate($pek);
        $pouzivatel->save();
        $pouzivatel->refresh();
        $informaciaData = [
            'titulok' => 'Ďalší testovací titulok',
            'obsah' => 'Ďalší testovací obsah.',
            'stav' => StavInformacieEnum::ZVEREJNENA,
            'zverejnit_pre_pouzivatelov_podla_role' => ['guest'],
            'planovany_cas_zverejnenia' => now()->addWeek(),
            'odoslat_email_pouzivatelom' => boolval(rand(0, 1)),
            'odoslat_push_notifikacie_pouzivatelom' => boolval(rand(0, 1)),
            'cas_zverejnenia' => rand(0, 1) ? now()->addDays(rand(30, 35)) : null,
            'odporucane' => boolval(rand(0, 1)),
        ];
        $informacia = Informacia::factory()
            ->make($informaciaData)
            ->vytvoril()
            ->associate($pouzivatel);
        $informacia->save();
        $informacia->refresh();
        $retrievedInformacia = Informacia::query()->findOrFail($informacia->id);

        $this->assertEquals($informacia->vytvoril, $retrievedInformacia->vytvoril);
        $this->assertEquals($informacia->vytvoril_id, $retrievedInformacia->vytvoril_id);
        $this->assertEquals($informacia->titulok, $retrievedInformacia->titulok);
        $this->assertEquals($informacia->obsah, $retrievedInformacia->obsah);
        $this->assertEquals($informacia->stav, $retrievedInformacia->stav);
        $this->assertEquals(
            $informaciaData['zverejnit_pre_pouzivatelov_podla_role'],
            $retrievedInformacia->zverejnit_pre_pouzivatelov_podla_role,
        );
        $this->assertEquals(
            $informaciaData['planovany_cas_zverejnenia']->toDateTimeString(),
            $retrievedInformacia->planovany_cas_zverejnenia->toDateTimeString(),
        );
        $this->assertEquals($informaciaData['odoslat_email_pouzivatelom'], $informacia->odoslat_email_pouzivatelom);
        $this->assertEquals(
            $informaciaData['odoslat_push_notifikacie_pouzivatelom'],
            $informacia->odoslat_push_notifikacie_pouzivatelom,
        );
        $this->assertEquals($informaciaData['odporucane'], $informacia->odporucane);

        if (is_null($informaciaData['cas_zverejnenia'])) {
            $this->assertNull($informaciaData['cas_zverejnenia']);
        } else {
            $this->assertEquals(
                $informaciaData['cas_zverejnenia']->toDateTimeString(),
                $informacia->cas_zverejnenia->toDateTimeString(),
            );
        }
    }

    protected function setUp(): void
    {
        parent::setUp();

        Event::fake();
    }
}
