<?php

declare(strict_types=1);

namespace KupShop\KupShopBundle\Context;

use KupShop\KupShopBundle\Entity\SectionPersistence;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;

class JsShopSectionContext implements ContextInterface, EmptiableContext
{
    private const JS_SHOP_SECTION_SESSION_KEY = 'jsShopSection';

    private ?SectionPersistence $value;
    private bool $loaded = false;

    public function __construct(
        protected readonly RequestStack $requestStack,
    ) {
    }

    public function activate(string|SectionPersistence $value): SectionPersistence
    {
        if (!($value instanceof SectionPersistence)) {
            $value = $this->decode($value);
        }

        $this->value = $value;
        $this->updatePersistentValue();

        return $this->value;
    }

    public function clearCache(): void
    {
        $this->loaded = false;
        $this->value = null;
    }

    public function forceEmpty(): void
    {
        $this->loaded = true;
        $this->value = null;
    }

    public function getActive(): ?SectionPersistence
    {
        if ($this->loaded === false) {
            $this->loadActive();
        }

        return $this->value;
    }

    private function loadActive(): void
    {
        $value = $this->getPersistentValue();
        if (!$value) {
            $this->value = null;

            return;
        }

        $this->value = !($persistence = $this->decode($value)) || $persistence->isDefault()
            ? null
            : $persistence;

        $this->loaded = true;
    }

    public function getActiveId(): ?string
    {
        $values = $this->getActive();
        if (!$values) {
            return null;
        }

        return json_encode($values);
    }

    public function getEncodedActiveId(): ?string
    {
        $id = $this->getActiveId();

        return $id ? md5($id) : null;
    }

    public function getSupported(): null
    {
        return null;
    }

    public function isValid(string $values): bool
    {
        return (bool) $this->decode($values);
    }

    protected function decode(string|array $data): ?SectionPersistence
    {
        try {
            return SectionPersistence::fromArray(is_string($data)
                ? json_decode_strict($data, true)
                : $data,
            );
        } catch (\JsonException) {
        }

        return null;
    }

    public function isEmpty(): bool
    {
        return $this->loaded && !$this->value;
    }

    private function clearPersistentValue(): void
    {
        $this->getRequest()->cookies->remove(self::JS_SHOP_SECTION_SESSION_KEY);
    }

    private function getPersistentValue(): ?string
    {
        return $this->getRequest()->cookies->get(self::JS_SHOP_SECTION_SESSION_KEY);
    }

    private function updatePersistentValue(): void
    {
        $this->getRequest()->cookies->set(
            self::JS_SHOP_SECTION_SESSION_KEY,
            json_encode($this->value),
        );
    }

    protected function getRequest(): Request
    {
        return $this->requestStack->getCurrentRequest();
    }
}
