package com.bcxin.wps.repository;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.bcxin.utils.BASE64Util;
import com.bcxin.utils.ConfigUtil;
import com.bcxin.wps.configs.WpsProperties;
import com.bcxin.wps.entity.File;
import com.bcxin.wps.entity.FileId;
import com.bcxin.wps.util.WpsFileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;

@Component
public class StorageRepository {
    private static Logger logger = LoggerFactory.getLogger(StorageRepository.class);

    private final Path dir;
    private static ConcurrentHashMap<String, Path> keys;
    private final WpsProperties wpsProperties;

    public StorageRepository(WpsProperties wpsProperties) {
        this.wpsProperties = wpsProperties;

        dir = FileUtil.mkdir(wpsProperties.getEditingDir()).toPath();

        if (keys == null) {
            synchronized (StorageRepository.class) {
                if (keys == null) {
                    keys = new ConcurrentHashMap<>(32);
                    Runtime.getRuntime().addShutdownHook(new Thread() {
                        @Override
                        public void run() {
                            try (Stream<Path> files = Files.walk(dir)) {
                                files.sorted(Comparator.reverseOrder()).forEach(WpsFileUtils::delete);
                                System.out.println("delete tmp dir succeed");
                            } catch (IOException ex) {
                                ex.printStackTrace();
                            }
                        }
                    });
                }
            }
        }
    }

    private String key(String id, long version) {
        return String.format("%s-%s", id, version);
    }

    public void save(File file, byte[] content) throws Exception {
        Objects.requireNonNull(file);
        Objects.requireNonNull(content);

        logger.error("执行如下的文件保存操作:{};version={};", file.getId(), file.getVersion());
        final String key = key(file.getId(), file.getVersion());

        Path parentPath = Paths.get(dir.toString(), key);
        FileUtil.mkdir(parentPath.toString());
        Path path = Paths.get(parentPath.toString(), file.getName());
        Files.deleteIfExists(path);
        Files.write(path, content);
        keys.put(key, path);

        if (file.getVersion() > 1) {
            Map<String, Object> paramMap = new HashMap<>();
            String _w_filepath = file.getUrl();
            if (file.isEncrypted()) {
                _w_filepath = BASE64Util.encryptBASE64(file.getUrl());
            }

            java.io.File fileContent = path.toFile();
            paramMap.put("file", fileContent);
            paramMap.put("filePath", _w_filepath);
            String sysUrl = ConfigUtil.getValue("pss_url") + "communicate/wps";
            String postSavedUrl = sysUrl + "/savefile";
            if (file.getUrl().contains("//www.pss360.cn/getResource.do")) {
                postSavedUrl = "https://www.pss360.cn/communicate/wps/savefile";
            }

            String result = HttpUtil.post(postSavedUrl, paramMap);
            logger.error(
                    "v3.目标服务器:{}(原本的配置={})-参数={};内容=[{}-存在={}]-原来的地址={}-文件保存响应结果:{}",
                    postSavedUrl, sysUrl,
                    _w_filepath,
                    fileContent.getAbsolutePath(),
                    fileContent.exists(),
                    file.getUrl(), result);

            if (!StringUtils.hasLength(result)) {
                throw new RuntimeException(String.format("文件(%s)保存到目标系统(%s)失败!", fileContent.getAbsolutePath(), postSavedUrl));
            }
        }
    }

    public byte[] findByFileId(FileId fileId) {
        Path path = keys.get(key(fileId.getId(), fileId.getVersion()));

        if (path == null) {
            throw new NoSuchElementException(String.format("No value present(fileId=%s;version=%s)", fileId.getId(), fileId.getVersion()));
        }

        byte[] content = WpsFileUtils.readAllBytes(path);
        logger.error("成功读取文件:{};version={};大小={}", fileId.getId(), fileId.getVersion(), content.length);
        return content;
    }

    public Map<String, Path> findAll() {
        final Map<String, Path> map = new HashMap<>(keys.size());
        map.putAll(keys);
        return map;
    }
}
