package com.agent.management.repository.json;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;

/**
 * JSON 文件存储引擎
 *
 * 职责：
 * 1. 提供基于 JSON 文件的持久化能力
 * 2. 通过读写锁保证并发安全
 * 3. 通过 .tmp + ATOMIC_MOVE 保证写入原子性
 *
 * 数据量假设：单文件不超过万级（配置类数据），全量加载到内存后操作。
 */
@Slf4j
public class JsonStore {

    private static final ObjectMapper MAPPER = new ObjectMapper()
            .registerModule(new JavaTimeModule())
            .enable(SerializationFeature.INDENT_OUTPUT);

    private final Path dataDir;

    public JsonStore(Path dataDir) {
        this.dataDir = dataDir.toAbsolutePath();
        try {
            Files.createDirectories(this.dataDir);
        } catch (IOException e) {
            throw new IllegalStateException("初始化 JSON 存储目录失败: " + this.dataDir, e);
        }
    }

    /**
     * 读取整个 JSON 文件并反序列化为 List
     * 文件不存在或解析失败时返回空列表
     */
    public <T> List<T> loadAll(String fileName, TypeReference<List<T>> typeRef) {
        Path file = dataDir.resolve(fileName);
        ReentrantReadWriteLock.ReadLock readLock = lockFor(fileName).readLock();
        readLock.lock();
        try {
            if (!Files.exists(file)) {
                return new ArrayList<>();
            }
            try {
                return MAPPER.readValue(file.toFile(), typeRef);
            } catch (IOException e) {
                log.error("[JsonStore] 读取文件失败，返回空列表: {}", file, e);
                return new ArrayList<>();
            }
        } finally {
            readLock.unlock();
        }
    }

    /**
     * 将整个 List 序列化写入 JSON 文件（原子替换）
     */
    public <T> void saveAll(String fileName, List<T> data) {
        Path file = dataDir.resolve(fileName);
        Path tmp = dataDir.resolve(fileName + ".tmp");
        ReentrantReadWriteLock.WriteLock writeLock = lockFor(fileName).writeLock();
        writeLock.lock();
        try {
            try {
                MAPPER.writeValue(tmp.toFile(), data);
            } catch (IOException e) {
                throw new IllegalStateException("[JsonStore] 写入临时文件失败: " + tmp, e);
            }
            try {
                Files.move(tmp, file, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
            } catch (IOException e) {
                // 某些文件系统不支持 ATOMIC_MOVE，降级为 REPLACE_EXISTING
                try {
                    Files.move(tmp, file, StandardCopyOption.REPLACE_EXISTING);
                } catch (IOException ex) {
                    throw new IllegalStateException("[JsonStore] 原子替换文件失败: " + file, ex);
                }
            }
        } finally {
            writeLock.unlock();
        }
    }

    /**
     * 对某个文件执行读操作（共享锁）
     */
    public <T> T read(String fileName, Function<List<?>, T> action) {
        ReentrantReadWriteLock.ReadLock readLock = lockFor(fileName).readLock();
        readLock.lock();
        try {
            // 这里仅作锁粒度控制，实际数据由调用方从 loadAll 获取
            return action.apply(null);
        } finally {
            readLock.unlock();
        }
    }

    // 每个文件一把读写锁
    private static final java.util.concurrent.ConcurrentHashMap<String, ReentrantReadWriteLock> LOCKS =
            new java.util.concurrent.ConcurrentHashMap<>();

    private ReentrantReadWriteLock lockFor(String fileName) {
        return LOCKS.computeIfAbsent(fileName, k -> new ReentrantReadWriteLock());
    }
}
