#pragma once

#include <unordered_map>
#include <list>
#include <mutex>
#include <memory>
#include <opencv2/core.hpp>
#include <fstream>
#include <string>
#include <filesystem>
#include "StitchStruct.h"

#if (__cplusplus < 201703L)
    #include <experimental/filesystem>
    namespace fs = std::experimental::filesystem;
#else
    namespace fs = std::filesystem;
#endif


// 
using KeyType = int;

// 通用文件缓存类:HASH部分目前没有针对不同类型的数据进行处理，多个键值一样的数据缓存会文件覆盖

// todo:落盘部分增加异步写入任务，提高性能


template <typename T>
class FileCache
{
public:
    explicit FileCache(size_t max_size, const std::string& cache_dir = "./cache");
    
    bool get(const KeyType& key, std::shared_ptr<T>& pData);
    void set(const KeyType& key, std::shared_ptr<T> pData);
    void clear();  // 新增清空缓存接口
    size_t getMemSize();

private:
    size_t max_size_;
    std::string cache_dir_;
    std::unordered_map<KeyType, std::pair<std::shared_ptr<T>, std::list<KeyType>::iterator>> cache_;
    std::list<KeyType> lru_list_;
    std::mutex mutex_;

    bool loadFromFile(const KeyType& key, T& frame);
    void saveToFile(const KeyType& key, const T& frame);
    void evictIfNeeded();

    std::string getCacheFilePath(const KeyType& key) const;
};




// 计算哈希值并转成字符串作为文件名
static std::string hashKey(const KeyType& key)
{
    std::hash<KeyType> hasher;
    return std::to_string(hasher(key));
}

template <typename T>
FileCache<T>::FileCache(size_t max_size, const std::string& cache_dir)
    : max_size_(max_size), cache_dir_(cache_dir)
{
    // 确保缓存目录存在
    if (!fs::exists(cache_dir_))
    {
        fs::create_directories(cache_dir_);
    }
}

template <typename T>
std::string FileCache<T>::getCacheFilePath(const KeyType& key) const
{
    return cache_dir_ + "/" + hashKey(key) + ".cache";  // 使用哈希作为文件名
}

template <typename T>
void FileCache<T>::saveToFile(const KeyType& key, const T& frame)
{
    std::string filePath = getCacheFilePath(key);

    if (fs::exists(filePath))
    {
        int a = 0;
    }
    std::ofstream ofs(filePath, std::ios::binary);
    if (ofs)
    {
        ofs.write(reinterpret_cast<const char*>(&frame), sizeof(frame));
    }
}

template <typename T>
bool FileCache<T>::loadFromFile(const KeyType& key, T& frame)
{
    std::string filePath = getCacheFilePath(key);
    std::ifstream ifs(filePath, std::ios::binary);
    if (!ifs)
    {
        return false;
    }
    ifs.read(reinterpret_cast<char*>(&frame), sizeof(frame));
    return true;
}

template <typename T>
void FileCache<T>::evictIfNeeded()
{
    if (cache_.size() < max_size_)
        return;

    // 删除最早使用的（LRU 末尾）
    KeyType oldest = lru_list_.back();
    lru_list_.pop_back();
    cache_.erase(oldest);

    std::cout << "Evicted cache from memory for key: " << oldest << std::endl;
}

template <typename T>
bool FileCache<T>::get(const KeyType& key, std::shared_ptr<T>& pData)
{
    std::lock_guard<std::mutex> lock(mutex_);

    // 检查内存缓存
    auto it = cache_.find(key);
    if (it != cache_.end())
    {
        // 缓存命中，更新 LRU 顺序
        lru_list_.erase(it->second.second);
        lru_list_.push_front(key);
        it->second.second = lru_list_.begin();

        pData = it->second.first;
        return true;
    }

    // 尝试从文件加载
    auto newData = std::make_shared<T>();
    if (loadFromFile(key, *newData))
    {
        evictIfNeeded();  // 超出内存容量时删除最早的

        // 插入新缓存到内存
        lru_list_.push_front(key);
        cache_[key] = { newData, lru_list_.begin() };
        pData = newData;
        return true;
    }

    return false;
}
template <typename T>
void FileCache<T>::set(const KeyType& key, std::shared_ptr<T> pData)
{
    std::lock_guard<std::mutex> lock(mutex_);

    // 如果已存在，则更新 LRU 位置
    auto it = cache_.find(key);
    if (it != cache_.end())
    {
        lru_list_.erase(it->second.second);
    }
    else
    {
        evictIfNeeded();  // 超出内存容量时删除最早的
    }

    // 插入新数据到内存
    lru_list_.push_front(key);
    cache_[key] = { pData, lru_list_.begin() };

    saveToFile(key, *pData);  // 将数据存储到磁盘
}

template <typename T>
size_t FileCache<T>::getMemSize()
{
    std::lock_guard<std::mutex> lock(mutex_);
    return cache_.size();
}

template <typename T>
void FileCache<T>::clear()
{
    std::lock_guard<std::mutex> lock(mutex_);
    
    // 清空内存缓存
    cache_.clear();
    lru_list_.clear();
    
    try 
    {
        // 检查缓存目录是否存在
        if (!fs::exists(cache_dir_))
        {
            return;
        }

        // 删除磁盘缓存文件
        for (const auto& entry : fs::directory_iterator(cache_dir_))
        {
            if (entry.path().extension() == ".cache")
            {
                try 
                {
                    if (!fs::remove(entry.path()))
                    {
                        std::cerr << "Failed to remove cache file: " << entry.path() << std::endl;
                    }
                }
                catch (const fs::filesystem_error& e)
                {
                    std::cerr << "Error removing cache file " << entry.path() << ": " << e.what() << std::endl;
                }
            }
        }
    }
    catch (const fs::filesystem_error& e)
    {
        std::cerr << "Error accessing cache directory: " << e.what() << std::endl;
    }
}
