<?php

namespace Soft_Tehnica\Freya_Sync_Service\Services;

use Soft_Tehnica\Freya_Sync_Service\Data\Location;
use Soft_Tehnica\Freya_Sync_Service\Data\Tax;
use Soft_Tehnica\Freya_Sync_Service\Data\UserAddress;
use Soft_Tehnica\Freya_Sync_Service\Data\UserAddressInputs;

class SessionService
{
    private ?string $userAddress = null;
    private ?string $locationUid = null;
    private bool $addressModalDismissed = false;
    private ?UserAddressInputs $userAddressInputs = null;
    private bool $isPickup = false;
    private ?UserAddress $address = null;
    private ?string $locationName = null;
    private ?Tax $tax = null;
    /** @var array<int, Location> $fetchedLocations */
    private array $fetchedLocations = [];
    private bool $_flashNeedLocation = false;

    public function getUserAddress(): ?string
    {
        return $this->userAddress;
    }

    public function setUserAddress(?string $userAddress): void
    {
        $this->userAddress = $userAddress;
        $this->updateSession();
    }

    public function getLocationUid(): ?string
    {
        return $this->locationUid;
    }

    public function setLocationUid(?string $locationUid): void
    {
        $this->locationUid = $locationUid;
        $this->updateSession();
    }

    public function isAddressModalDismissed(): bool
    {
        return $this->addressModalDismissed;
    }

    public function setAddressModalDismissed(bool $addressModalDismissed): void
    {
        $this->addressModalDismissed = $addressModalDismissed;
        $this->updateSession();
    }

    public function getUserAddressInputs(): ?UserAddressInputs
    {
        return $this->userAddressInputs;
    }

    public function setUserAddressInputs(?UserAddressInputs $userAddressInputs): void
    {
        $this->userAddressInputs = $userAddressInputs;
        $this->updateSession();
    }

    public function isPickup(): bool
    {
        return $this->isPickup;
    }

    public function setIsPickup(bool $isPickup): void
    {
        $this->isPickup = $isPickup;
        $this->updateSession();
    }

    public function getAddress(): ?UserAddress
    {
        return $this->address ?? null;
    }

    public function setAddress(?UserAddress $userAddress): void
    {
        $this->address = $userAddress;
        $this->updateSession();
    }

    public function getLocationName(): ?string
    {
        return $this->locationName ?? null;
    }

    public function setLocationName(?string $locationName): void
    {
        $this->locationName = $locationName;
        $this->updateSession();
    }

    public function getTax(): ?Tax
    {
        return $this->tax ?? null;
    }

    public function setTax(?Tax $tax): void
    {
        $this->tax = $tax;
        $this->updateSession();
    }

    public function flashNeedLocation(): bool
    {
        return $this->_flashNeedLocation;
    }

    public function setFlashNeedLocation(bool $value): void
    {
        if ($value === $this->_flashNeedLocation) {
            return;
        }

        $this->_flashNeedLocation = $value;
        $this->updateSession();
    }

    private function updateSession(): void
    {
        if (!isset($_SESSION['freya-sync-service'])) {
            $_SESSION['freya-sync-service'] = [];
        }
        $session = [];
        $session['userAddress'] = $this->userAddress;
        $session['locationUid'] = $this->locationUid;
        $session['locationName'] = $this->locationName;
        $session['isPickup'] = $this->isPickup;
        $session['addressModalWasDismissed'] = $this->addressModalDismissed;

        if (count($this->fetchedLocations) > 0) {
            $session['fetchedLocations-2'] = serialize($this->fetchedLocations);
        }
        if (isset($this->userAddressInputs)) {
            $session['userAddressInputs'] = serialize($this->userAddressInputs);
        }
        if (isset($this->address)) {
            $session['geo'] = serialize($this->address);
        }
        if (isset($this->tax)) {
            $session['tax'] = serialize($this->tax);
        }

        $_SESSION['freya-sync-service'] = $session;
    }

    private static SessionService $instance;

    protected function __construct()
    {
    }

    /**
     * @return array<int, array{name: string, uid: string}>
     */
    public function getFetchedLocations(): array
    {
        return $this->fetchedLocations;
    }

    /**
     * @param array<int, Location> $fetchedLocations
     * @return void
     */
    public function setFetchedLocations(array $fetchedLocations): void
    {
        $this->fetchedLocations = $fetchedLocations;
        $this->updateSession();
    }

    protected function __clone()
    {
    }

    public function updateSessionWithActiveShipping(bool $delivery, bool $pickup): void
    {
        if ($delivery && $pickup) {
            return;
        }

        if ($delivery) {
            $this->isPickup = false;
        }

        if ($pickup) {
            $this->address = null;
            $this->userAddressInputs = null;
            $this->userAddress = null;
            $this->tax = null;
        }

        $this->updateSession();
    }

    public function refreshSession(): void
    {
        if (!isset($_SESSION['freya-sync-service'])) {
            $_SESSION['freya-sync-service'] = [];
        }
        if (!isset($_SESSION['freya-sync-service']['CREATED'])) {
            $_SESSION['freya-sync-service']['CREATED'] = time();
            return;
        }
        if (time() - $_SESSION['freya-sync-service']['CREATED'] > 3600) {
            // If session was created > 1 hour ago
            session_regenerate_id(true);
            $_SESSION['freya-sync-service']['CREATED'] = time();
            $this->updateSession();
        }
    }

    /**
     * Clears settings that need refetching on a new order
     *
     * @return void
     */
    public function clearSession(): void
    {
        $this->locationUid = null;
        $this->locationName = null;
        $this->tax = null;
        $this->addressModalDismissed = false;
        $this->fetchedLocations = [];
    }

    public function loadSession(): void
    {
        if (is_null($_SESSION) || count($_SESSION) === 0) {
            return;
        }
        $session = $_SESSION['freya-sync-service'] ?? [];
        if (count($session) === 0) {
            return;
        }
        $this->userAddress = $session['userAddress'] ?? null;
        $this->addressModalDismissed = $session['addressModalWasDismissed'] ?? false;
        $this->locationUid = $session['locationUid'] ?? null;
        $this->isPickup = $session['isPickup'] ?? false;
        $this->locationName = $session['locationName'] ?? null;
        if (isset($session['userAddressInputs'])) {
            $this->userAddressInputs = unserialize($session['userAddressInputs']);
        } else {
            $this->userAddressInputs = null;
        }
        if (isset($session['geo'])) {
            $this->address = unserialize($session['geo']);
        } else {
            $this->address = null;
        }
        if (isset($session['tax'])) {
            $this->tax = unserialize($session['tax']);
        } else {
            $this->tax = null;
        }
        if (isset($session['fetchedLocations-2'])) {
            $this->fetchedLocations = unserialize($session['fetchedLocations-2']);
        }
    }

    public static function get(): SessionService
    {
        if (!isset(static::$instance)) {
            static::$instance = new SessionService();
        }
        return static::$instance;
    }
}