package cc.smtweb.system.bpm.util;

import cc.smtweb.framework.core.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;

import java.io.File;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Random;

/**
 * 动态文件〈文件路径〉
 *
 * @author kevin
 * @since 1.0.0
 */
@Slf4j
public class FileDynPath extends FileFixPath {
    // 目录允许的最大文件数量，避免批量导入文件时文件太多
    private static final int MAX_FILE_COUNT = 2000;
    private static final int MAX_DIR_COUNT = 100000;
    private long startTime;
    private long endTime;
    private final SimpleDateFormat sdf;
    // 文件数量
    private int fileCount;
    // 目录子索引
    private int pathIndex;

    public FileDynPath(String rootPath, String typeDir, SimpleDateFormat sdf) {
        super(rootPath, typeDir);
        this.sdf = sdf;
    }

    /**
     * 返回日期路径字符串
     */
    @Override
    public FilePathInfo makeDatePath(long fileId, String fileExt) {
        long now = System.currentTimeMillis();
        String fileName;

        // 如果不在就需要重新创建子目录
        if (now < startTime || now >= endTime) {
            startTime = DateUtil.getTimesmorning(now);
            endTime = startTime + DateUtils.MILLIS_PER_DAY;

            this.path = this.typeDir + "/" + sdf.format(new Timestamp(now));
            createFolder(rootPath + this.path);
        }

        // 如果文件数量太大就需要创建新子目录
        while (this.fileCount >= MAX_FILE_COUNT) {
            this.pathIndex++;
            if (this.pathIndex > MAX_DIR_COUNT) {
                throw new RuntimeException("dir is two many");
            }

            createFolder(rootPath + getSubPath());
        }

        Random random = new Random();
        int randomId = random.nextInt(Integer.MAX_VALUE);

        fileName = Long.toHexString(fileId) + "_" + Integer.toHexString(randomId) + fileExt;

        return new FilePathInfo(rootPath, getSubPath(), now, fileName, fileId);
    }

    private String getSubPath() {
        if (this.pathIndex > 0) {
            return String.format("%s%02d/%04d", this.path, MAX_DIR_COUNT / 1000, this.pathIndex % 1000);
        }

        return this.path;
    }

    private boolean createFolder(String path) {
        File file = new File(path);
        if (file.exists()) {
            if (!file.isDirectory()) {
                return false;
            }

            File[] list = file.listFiles();
            if (list != null) {
                this.fileCount = list.length;
            } else {
                this.fileCount = 0;
            }

            return true;
        }

        if (!file.mkdirs()) {
            log.error("unable to create folders {}.", rootPath + this.path);
            return false;
        }

        log.debug("create folders {}.", file);
        this.fileCount = 0;

        return true;
    }
}
