<?php

namespace helpers;

require_once WD . '/modules/xlvask/interfaces/xlvask_cache_i.php';

use Exception;
use xlvask\interfaces\xlvask_cache_i;

class xlvask_cache implements xlvask_cache_i
{
    public function __construct()
    {
    }

    /**
     * @inheritDoc
     * @throws Exception If there is an error encoding the customer data to JSON.
     */
    public function setCustomerCache(int $customer_number, xlvask_customer $customer): void
    {
        $customer_data = json_encode($customer, JSON_THROW_ON_ERROR);
        redis->set(self::getCustomerCacheKey($customer_number), $customer_data);
        redis->expire(self::getCustomerCacheKey($customer_number), 3600); // Set cache expiration to 1 hour
    }

    protected function getCustomerCacheKey(int $customer_number): string
    {
        return 'xlvask_customer_' . $customer_number;
    }

    /**
     * @inheritDoc
     * @throws Exception
     */
    public function clearCustomerCache(int $customer_number): void
    {
        if (self::isCustomerCached($customer_number)) {
            redis->delete(self::getCustomerCacheKey($customer_number));
        } else {
            throw new Exception("Customer with number $customer_number is not cached.");
        }
    }

    /**
     * @inheritDoc
     */
    public function isCustomerCached(int $customer_number): bool
    {
        return (redis->exists(self::getCustomerCacheKey($customer_number)));
    }

    /**
     * @inheritDoc
     */
    public function clearAllCustomerCache(): void
    {
        $keys = redis->get_keys('xlvask_customer_*');
        redis->clear_keys($keys);
    }

    /**
     * @inheritDoc
     * @throws Exception If there are issues retrieving customers.
     */
    public function getAllCachedCustomers(): array
    {
        $keys = redis->get_keys('xlvask_customer_*');
        $customers = [];
        foreach ( $keys as $key ) {
            $customer_data = redis->get($key);
            if ($customer_data) {
                $customer_data = json_decode($customer_data, true);
                $tmp = new xlvask_customer();
                // Assign the properties shared by the xlvask_customer class.
                foreach ( $customer_data as $property => $value ) {
                    if (property_exists($tmp, $property)) {
                        $tmp->{$property} = $value;
                    }
                }
                $customers[] = $tmp; // Add the xlvask_customer object to the array
            } else {
                throw new Exception("Failed to retrieve customer data for key: $key");
            }
        }
        return $customers;
    }

    /**
     * @inheritDoc
     */
    public function getCachedCustomerCount(): int
    {
        $keys = redis->get_keys('xlvask_customer_*');
        return count($keys);
    }

    /**
     * @inheritDoc
     * @throws Exception
     */
    public function getCachedCustomersByCustomerNumbers(array $customer_numbers, bool $allow_missing = false): array
    {
        $result = [];
        foreach ( $customer_numbers as $customer_number ) {
            if (self::isCustomerCached($customer_number)) {
                $result[$customer_number] = $this->getCustomerCache($customer_number);
            } elseif ($allow_missing) {
                $result[$customer_number] = null; // or handle as needed
            } else {
                throw new Exception("Customer with number $customer_number is not cached.");
            }
        }
        return $result;
    }

    /**
     * @inheritDoc
     */
    public function getCustomerCache(int $customer_number): xlvask_customer
    {
        if (self::isCustomerCached($customer_number)) {
            $customer_data = (object)json_decode(redis->get(self::getCustomerCacheKey($customer_number)), true);
            $tmp = new xlvask_customer();
            // Assign the properties shared by the xlvask_vehicle class.
            foreach ( $customer_data as $key => $value ) {
                if (property_exists($tmp, $key)) {
                    $tmp->{$key} = $value;
                }
            }
            return $tmp; // Return the xlvask_customer object
        }
        throw new Exception("Customer with number $customer_number is not cached.");
    }

    /**
     * @inheritDoc
     */
    public function getVehicleCache(string $registration): xlvask_vehicle
    {
        if (self::isVehicleCached($registration)) {
            $vehicle_data = (object)json_decode(redis->get('xlvask_vehicle_' . $registration), true);
            $tmp = new xlvask_vehicle();
            // Assign the properties shared by the xlvask_vehicle class.
            foreach ( $vehicle_data as $key => $value ) {
                if (property_exists($tmp, $key)) {
                    $tmp->{$key} = $value;
                }
            }
            return $tmp; // Return the xlvask_vehicle object
        }
        throw new Exception("Vehicle with registration $registration is not cached.");
    }

    /**
     * @inheritDoc
     */
    public function isVehicleCached(string $registration): bool
    {
        return (redis->exists('xlvask_vehicle_' . $registration));
    }

    /**
     * @inheritDoc
     * @throws Exception If there is an error encoding the vehicle data to JSON.
     * @see xlvask_vehicle
     */
    public function setVehicleCache(string $registration, xlvask_vehicle $vehicle): void
    {
        $vehicle_data = json_encode($vehicle, JSON_THROW_ON_ERROR);
        redis->set('xlvask_vehicle_' . $registration, $vehicle_data);
        redis->expire('xlvask_vehicle_' . $registration, 3600); // Set cache expiration to 1 hour
    }

    /**
     * @inheritDoc
     */
    public function clearVehicleCache(string $registration): void
    {
        if (self::isVehicleCached($registration)) {
            redis->delete('xlvask_vehicle_' . $registration);
        } else {
            throw new Exception("Vehicle with registration $registration is not cached.");
        }
    }

    /**
     * @inheritDoc
     */
    public function clearAllVehicleCache(): void
    {
        $keys = redis->get_keys('xlvask_vehicle_*');
        redis->clear_keys($keys);
    }

    /**
     * @inheritDoc
     */
    public function getAllCachedVehicles(): array
    {
        $keys = redis->get_keys('xlvask_vehicle_*');
        $vehicles = [];
        foreach ( $keys as $key ) {
            $vehicle_data = redis->get($key);
            if ($vehicle_data) {
                $vehicle_data = json_decode($vehicle_data, true);
                $tmp = new xlvask_vehicle();
                // Assign the properties shared by the xlvask_vehicle class.
                foreach ( $vehicle_data as $property => $value ) {
                    if (property_exists($tmp, $property)) {
                        $tmp->{$property} = $value;
                    }
                }
                $vehicles[] = $tmp; // Add the xlvask_vehicle object to the array
            } else {
                throw new Exception("Failed to retrieve vehicle data for key: $key");
            }
        }
        return $vehicles;
    }
}