package cn.reghao.tnb.oss.store.disk;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileStore;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;

/**
 * @author reghao
 * @date 2022-05-23 18:21:22
 */
public class LocalStores {
    private static final Map<String, LocalStore> storeMap = new HashMap<>();
    private static final Map<String, Map<String, StoreDir>> storeDirMap = new HashMap<>();

    public static void init(List<String> storeDirs) throws IOException {
        Map<String, String> map = new HashMap<>();
        for (String storeDir : storeDirs) {
            FileStore fileStore = Files.getFileStore(Path.of(storeDir));
            String logicalDisk = fileStore.name();
            String prevValue = map.putIfAbsent(logicalDisk, storeDir);
            if (prevValue == null) {
                long total = fileStore.getTotalSpace();
                long available = fileStore.getUsableSpace();
                LocalStore localStore = new LocalStore(logicalDisk, storeDir, total, available, 0.9);
                storeMap.put(storeDir, localStore);
                storeDirMap.computeIfAbsent(storeDir, k -> new HashMap<>());
                createSubDirs(storeDir);
            } else {
                String msg = String.format("%s's mounted directory %s has already associated with %s", logicalDisk, storeDir, prevValue);
                System.out.println(msg);
            }
        }
    }

    private static void createSubDirs(String storeDir) throws IOException {
        int total = 128;
        for (int i = 0; i < total; i++) {
            for (int j = 0; j < total; j++) {
                String baseDir = String.format("%s/%s/%s/", storeDir, i, j);
                File dir = new File(baseDir);
                if (!dir.exists() && !dir.mkdirs()) {
                    String msg = String.format("create %s failed", dir);
                    throw new IOException(msg);
                }

                String baseDir1 = dir.getAbsolutePath();
                storeDirMap.get(storeDir).put(baseDir1, new StoreDir(baseDir1));
            }
        }
    }

    // TODO 优化算法, 处理异常
    public static LocalStore getMaxStore(long size) {
        Map<String, Long> map = new HashMap<>();
        for (Map.Entry<String, LocalStore> entry : storeMap.entrySet()) {
            String storeDir = entry.getKey();
            LocalStore localStore = entry.getValue();
            long currentAvailable = localStore.getAvailSpace() - size;
            map.put(storeDir, currentAvailable);
        }

        List<String> storeDirs = new ArrayList<>();
        // storeDirs 中的元素升序排列
        map.entrySet().stream()
                .sorted(Map.Entry.comparingByValue())
                .forEachOrdered(b -> storeDirs.add(b.getKey()));

        String maxDisk = storeDirs.get(storeDirs.size()-1);
        LocalStore localStore = storeMap.get(maxDisk);
        localStore.setCurrentAvailSpace(map.get(maxDisk));
        return localStore;
    }
    
    public static List<StoreDir> getSubDirs(String storeDir) {
        return new ArrayList<>(storeDirMap.get(storeDir).values());
    }

    public static List<LocalStore> getLocalStores() {
        return new ArrayList<>(storeMap.values());
    }
}
