package com.seezoon.admin.modules.sys.service;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.seezoon.admin.framework.file.FileService;
import com.seezoon.admin.framework.service.AbstractCrudService;
import com.seezoon.dao.modules.sys.SysFileDao;
import com.seezoon.dao.modules.sys.entity.SysFile;
import com.seezoon.dao.modules.sys.entity.SysFileCondition;
import com.seezoon.framework.component.file.FileInfo;

import lombok.RequiredArgsConstructor;

/**
 * 文件
 *
 * @author seezoon-generator 2021年1月2日 上午1:04:41
 */
@Service
@RequiredArgsConstructor
public class SysFileService extends AbstractCrudService<SysFileDao, SysFile, String> {

    public static final String COMMA = ",";
    private final FileService fileService;

    @Transactional(readOnly = true)
    public List<SysFile> findByIds(@NotEmpty List<String> ids) {
        SysFileCondition sysFileCondition = new SysFileCondition();
        sysFileCondition.setIds(ids);
        return this.find(sysFileCondition);
    }

    public FileInfo upload(@NotEmpty String originalFilename, @NotEmpty String contentType, long size,
        @NotNull InputStream in) throws IOException {
        // 新命名
        String fileId = createFileId();
        String newName = rename(fileId, originalFilename);
        String relativePath = createRelativeDirectory() + newName;
        fileService.upload(relativePath, contentType, in);
        // 入库
        SysFile sysFile = new SysFile();
        sysFile.setId(fileId);
        sysFile.setName(originalFilename);
        sysFile.setContentType(contentType);
        sysFile.setFileSize((int)size);
        sysFile.setRelativePath(relativePath);
        this.save(sysFile);
        return new FileInfo(fileService.getUrl(relativePath), relativePath, originalFilename);
    }

    /**
     * 查询文件详细信息，会自动排序
     *
     * @param relativePaths
     * @param includeFileName
     * @return
     */
    @Transactional(readOnly = true)
    public List<FileInfo> info(@NotBlank String relativePaths, boolean includeFileName) {
        String[] relativePathArray = StringUtils.split(relativePaths, COMMA);
        List<String> ids = new ArrayList<>();
        Map<String, String> idMapRelativePath = new HashMap<>();
        List<FileInfo> fileInfos = new ArrayList<>();
        for (String relativePath : relativePathArray) {
            String id = fileService.getId(relativePath);
            ids.add(id);
            idMapRelativePath.put(relativePath, id);
            if (!includeFileName) {
                fileInfos.add(new FileInfo(fileService.getUrl(relativePath), relativePath, null));
            }
        }

        if (includeFileName) {
            Map<String, SysFile> relativePathMapFile = this.findByIds(ids).stream()
                .collect(Collectors.toMap(SysFile::getRelativePath, Function.identity(), (k1, k2) -> k1));
            for (String relativePath : relativePathArray) {
                SysFile sysFile = relativePathMapFile.get(relativePath);
                if (null == sysFile) {
                    logger.error("file not exists relativePath=[{}]", relativePath);
                    continue;
                }
                fileInfos.add(new FileInfo(fileService.getUrl(sysFile.getRelativePath()), sysFile.getRelativePath(),
                    sysFile.getName()));
            }
        }
        return fileInfos;
    }

    /**
     * 生成文件id
     *
     * @return
     */
    private String createFileId() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 生成新的文件名
     *
     * @param fileId
     * @param originalFileName
     * @return
     */
    public String rename(String fileId, String originalFileName) {
        return fileId + getFileSuffix(originalFileName);
    }

    /**
     * 获取文件后缀
     *
     * @param fileName
     *            包含后缀
     * @return
     */
    public String getFileSuffix(String fileName) {
        Assert.hasText(fileName, "fileName must not be empty");
        String suffix = "";
        int lastIndex = -1;
        if (-1 != (lastIndex = fileName.lastIndexOf("."))) {
            suffix = fileName.substring(lastIndex);
        }
        return suffix;
    }

    /**
     * 生成相对目录
     *
     * @return
     */
    private String createRelativeDirectory() {
        LocalDate now = LocalDate.now();
        return "/" + now.getYear() + "/" + now.getMonthValue() + "/" + now.getDayOfMonth() + "/";
    }
}
