package com.zombie.game.server;

import com.google.gson.Gson;
import com.zombie.game.model.MapData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.file.*;
import java.util.*;

/**
 * Storage service for game maps (save, load, list, delete) / 地图存储服务（保存、加载、列出、删除）
 */
public class MapStorage {
    // Logger for map operations / 地图操作日志记录器
    private static final Logger logger = LoggerFactory.getLogger(MapStorage.class);
    // Directory where map files are stored / 地图文件存储目录
    private static final String MAPS_DIR = "maps";
    // JSON serializer/deserializer / JSON序列化/反序列化工具
    private final Gson gson;
    // In-memory cache of loaded maps / 已加载地图的内存缓存
    private final Map<String, MapData> cache;

    // Constructor: initializes storage and ensures maps directory exists / 构造函数：初始化存储并确保地图目录存在
    public MapStorage() {
        this.gson = new Gson();
        this.cache = new HashMap<>();
        ensureMapsDir();
    }

    // Create maps directory if it doesn't exist / 如果地图目录不存在则创建
    private void ensureMapsDir() {
        Path mapsPath = Paths.get(MAPS_DIR);
        if (!Files.exists(mapsPath)) {
            try {
                Files.createDirectories(mapsPath);
            } catch (IOException e) {
                logger.error("Failed to create maps directory", e);
            }
        }
    }

    // Save a map to disk and cache / 将地图保存到磁盘并缓存
    public MapData save(MapData mapData) {
        // Assign ID if missing / 如果缺少ID则生成
        if (mapData.getId() == null || mapData.getId().isEmpty()) {
            mapData.setId(UUID.randomUUID().toString().substring(0, 8));
        }
        // Set default name if missing / 如果缺少名称则使用默认值
        if (mapData.getName() == null || mapData.getName().isEmpty()) {
            mapData.setName("untitled");
        }

        String filename = mapData.getId() + ".json";
        Path filePath = Paths.get(MAPS_DIR, filename);

        try (Writer writer = Files.newBufferedWriter(filePath)) {
            gson.toJson(mapData, writer);
            cache.put(mapData.getId(), mapData);
            logger.info("Map saved: {} ({})", mapData.getName(), mapData.getId());
            return mapData;
        } catch (IOException e) {
            logger.error("Failed to save map: {}", mapData.getId(), e);
            throw new RuntimeException("Failed to save map", e);
        }
    }

    // Load a map from cache or disk / 从缓存或磁盘加载地图
    public MapData load(String id) {
        // Check cache first / 先检查缓存
        MapData cached = cache.get(id);
        if (cached != null) {
            return cached;
        }

        String filename = id + ".json";
        Path filePath = Paths.get(MAPS_DIR, filename);

        if (!Files.exists(filePath)) {
            return null;
        }

        try (Reader reader = Files.newBufferedReader(filePath)) {
            MapData mapData = gson.fromJson(reader, MapData.class);
            cache.put(id, mapData);
            return mapData;
        } catch (IOException e) {
            logger.error("Failed to load map: {}", id, e);
            return null;
        }
    }

    // List all maps from disk / 列出磁盘上的所有地图
    public List<MapData> listMaps() {
        List<MapData> maps = new ArrayList<>();
        Path mapsPath = Paths.get(MAPS_DIR);

        if (!Files.exists(mapsPath)) {
            return maps;
        }

        try (DirectoryStream<Path> stream = Files.newDirectoryStream(mapsPath, "*.json")) {
            for (Path file : stream) {
                try (Reader reader = Files.newBufferedReader(file)) {
                    MapData mapData = gson.fromJson(reader, MapData.class);
                    maps.add(mapData);
                } catch (IOException e) {
                    logger.warn("Failed to read map file: {}", file);
                }
            }
        } catch (IOException e) {
            logger.error("Failed to list maps", e);
        }

        return maps;
    }

    // Delete a map from disk and cache / 从磁盘和缓存中删除地图
    public boolean delete(String id) {
        String filename = id + ".json";
        Path filePath = Paths.get(MAPS_DIR, filename);

        try {
            boolean deleted = Files.deleteIfExists(filePath);
            if (deleted) {
                cache.remove(id);
                logger.info("Map deleted: {}", id);
            }
            return deleted;
        } catch (IOException e) {
            logger.error("Failed to delete map: {}", id, e);
            return false;
        }
    }
}
