#pragma once

#include "lru_cache.h"
#include "cluster.h"

#include <paritypp/client.h>
#include <paritypp/server.h>

#include <crypto/sha.h>

#include <cstdint>
#include <memory>
#include <string>
#include <vector>

namespace mediadb {

// Fragment size for large previews: 10 MB
static constexpr size_t PREVIEW_FRAGMENT_SIZE = 10ULL * 1024 * 1024;

// Cluster-shared preview cache (L2) with fragment support.
//
// Uses store_id=1 on the existing cluster parity server (same port).
// Local block_store is a memory_block_store with byte-budget LRU eviction.
//
// Small previews (≤ PREVIEW_FRAGMENT_SIZE) are stored as a single parity group.
// Large previews are split into 10 MB fragments, each in its own parity group,
// plus a metadata group describing the layout.
//
// L1 (BlobCache) sits in front — this class handles L1 miss → L2 lookup → render.
class PreviewCache {
public:
    // cluster: the existing Cluster instance (to register store + create client)
    // max_bytes_per_node: byte budget for the local memory_block_store
    PreviewCache(Cluster& cluster, size_t max_bytes_per_node);

    // Create client connections and warm up. Must be called post-fork.
    void start();

    // Try to retrieve a preview from L2.
    // Returns the assembled blob, or nullptr on miss.
    // On hit, also inserts fragment(s) into L1.
    std::shared_ptr<const BlobValue> get(const std::string& key, BlobCache& l1);

    // Store a rendered preview into L2 (and L1).
    // Automatically fragments if > PREVIEW_FRAGMENT_SIZE.
    void put(const std::string& key, const BlobValue& blob, BlobCache& l1);

private:
    // Deterministic group_id from a cache key string
    static uint64_t cache_group_id(const std::string& key);

    // Fragment metadata stored as parity group: [4B num_chunks][8B total_size][content_type\0][etag\0]
    struct FragMeta {
        uint32_t num_chunks;
        uint64_t total_size;
        std::string content_type;
        std::string etag;
    };

    static std::vector<uint8_t> encode_meta(const FragMeta& m);
    static bool decode_meta(const std::vector<uint8_t>& data, FragMeta& out);

    static constexpr uint8_t STORE_ID = 1; // preview cache store

    std::shared_ptr<paritypp::memory_block_store> store_;
    std::unique_ptr<paritypp::client> client_;
};

} // namespace mediadb
