<?php

namespace PortalPeople\virtualstock\components;

use yii\base\Component;
use Yii;

/**
 * Response cache for VirtualStock API calls.
 *
 * Caches GET responses to reduce redundant API requests and avoid hitting the
 * 60 req/min rate limit. Cache is keyed by endpoint + query parameters.
 *
 * Only GET responses should be cached — mutation operations (POST/PATCH/DELETE)
 * must not be cached and should call flush() or invalidatePrefix() as needed.
 *
 * Usage:
 *   $cached = $cache->get('orders', ['limit' => 10]);
 *   if ($cached === null) {
 *       $data = $client->getOrdersUpdatedSince(...);
 *       $cache->set('orders', ['limit' => 10], $data);
 *   }
 */
class ApiCache extends Component
{
    /** Cache TTL in seconds for order listings. */
    public int $ordersTtl = 60;

    /** Cache TTL in seconds for product/stock data. */
    public int $productsTtl = 300;

    /** Cache TTL in seconds for supplier/retailer data. */
    public int $suppliersTtl = 3600;

    /** Default TTL when no category-specific one is used. */
    public int $defaultTtl = 120;

    /** Cache key prefix to namespace all entries. */
    public string $keyPrefix = 'vs_api_';

    /**
     * Retrieve a cached API response.
     *
     * @param string               $endpoint  e.g. 'orders', 'products', 'suppliers'
     * @param array<string, mixed> $params    Query parameters used in the original request
     * @return array<string, mixed>|null  Cached data, or null on miss
     */
    public function get(string $endpoint, array $params = []): ?array
    {
        $key  = $this->buildKey($endpoint, $params);
        $data = Yii::$app->cache->get($key);

        return is_array($data) ? $data : null;
    }

    /**
     * Store an API response in cache.
     *
     * @param string               $endpoint
     * @param array<string, mixed> $params
     * @param array<string, mixed> $data
     */
    public function set(string $endpoint, array $params, array $data): void
    {
        $key = $this->buildKey($endpoint, $params);
        $ttl = $this->resolveTtl($endpoint);
        Yii::$app->cache->set($key, $data, $ttl);
    }

    /**
     * Delete a specific cached response.
     *
     * @param array<string, mixed> $params
     */
    public function delete(string $endpoint, array $params = []): void
    {
        $key = $this->buildKey($endpoint, $params);
        Yii::$app->cache->delete($key);
    }

    /**
     * Flush all VirtualStock API cache entries.
     * Note: Only available with cache backends that support TagDependency or
     * full flush. Falls back to a no-op for cache drivers that don't support it.
     */
    public function flush(): void
    {
        Yii::$app->cache->flush();
    }

    /**
     * Build a stable cache key from endpoint + params.
     */
    public function buildKey(string $endpoint, array $params = []): string
    {
        ksort($params);
        return $this->keyPrefix . md5($endpoint . ':' . serialize($params));
    }

    /**
     * Resolve TTL based on the endpoint category.
     */
    private function resolveTtl(string $endpoint): int
    {
        $endpoint = strtolower($endpoint);

        if (str_contains($endpoint, 'order')) {
            return $this->ordersTtl;
        }
        if (str_contains($endpoint, 'product') || str_contains($endpoint, 'stock')) {
            return $this->productsTtl;
        }
        if (str_contains($endpoint, 'supplier') || str_contains($endpoint, 'retailer')) {
            return $this->suppliersTtl;
        }

        return $this->defaultTtl;
    }
}
