package com.github.lybgeek.plugin.util;


import cn.hutool.core.util.ArrayUtil;
import lombok.Cleanup;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.springframework.core.io.support.SpringFactoriesLoader;

import java.io.*;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.stream.Collectors;

@Slf4j
public final class SpringFactoriesFileUtils {

    private SpringFactoriesFileUtils(){}


    /**
     * 读取 spring.factories 文件
     *
     * @return MultiSetMap
     * @throws IOException 异常信息
     */
    @SneakyThrows
    public static Map<String, Set<String>> readFactoriesFile(InputStream input)  {
        // 读取 spring.factories 内容
        //利用PropertiesConfiguration取配置文件中key重复的内容，而不被覆盖
        PropertiesConfiguration properties = new PropertiesConfiguration();
        properties.read(new InputStreamReader(input));
        Map<String, Set<String>> multiSetMap = new LinkedHashMap<>();
        Iterator<String> keys = properties.getKeys();
        while(keys.hasNext()) {
            String key = keys.next();
            String[] values = properties.getStringArray(key);
            Set<String> collectSet = new LinkedHashSet<>();
            buildKeyValues(values, collectSet);
            multiSetMap.put(key,collectSet);
        }
        return multiSetMap;

    }

    private static void buildKeyValues(String[] values, Set<String> collectSet) {
        if(ArrayUtil.isNotEmpty(values)){
            for (String value : values) {
                if(value.contains(",")){
                    String[] valueArr = value.split(",");
                    Set<String> valueSet = Arrays.stream(valueArr)
                            .filter(v -> !v.isEmpty())
                            .map(String::trim)
                            .collect(Collectors.toSet());
                    collectSet.addAll(valueSet);
                }else{
                    collectSet.add(value);
                }

            }
        }
    }

    /**
     * 写入 spring.factories 文件
     *
     * @throws IOException 异常信息
     */
    public static void writeFactoriesFile(String factoriesBaseClassPathDir,String finalJarName) throws IOException {
        String jarFilePath = String.format(factoriesBaseClassPathDir + "/target/" + finalJarName).replace("\\", "/").replaceAll("//+", "/");
        if(!jarFilePath.endsWith(".jar")){
            jarFilePath = jarFilePath + ".jar";
        }
        JarFile jarFile = new JarFile(jarFilePath);
        if(jarFile != null){
            List<JarEntry> jarFiles = jarFile.stream().collect(Collectors.toList());
            @ Cleanup FileOutputStream fos = new FileOutputStream(jarFile.getName(), true);
            @ Cleanup JarOutputStream jos = new JarOutputStream(fos);
            for (JarEntry jarEntry : jarFiles) {
                if(jarEntry.getName().startsWith(SpringFactoriesLoader.FACTORIES_RESOURCE_LOCATION)){
                    try {
                        @ Cleanup InputStream input = jarFile.getInputStream(jarEntry);
                        Map<String, Set<String>> factoriesMap = readFactoriesFile(input);
                        jos.putNextEntry(new JarEntry(jarEntry.getName()));
                        generateFactoriesContent(factoriesMap,jos);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }else{
                    //表示将该JarEntry写入jar文件中 也就是创建该文件夹和文件
                    jos.putNextEntry(new JarEntry(jarEntry));
                    jos.write(streamToByte(jarFile.getInputStream(jarEntry)));
                }
            }


        }
    }

    private static byte[] streamToByte(InputStream inputStream) {
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        try {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = inputStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            outSteam.close();
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return outSteam.toByteArray();
    }





    private static void generateFactoriesContent(Map<String, Set<String>> factories,
                                                 OutputStream output) throws IOException {
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, "UTF-8"));
        writer.write("# Generated by LYB-GEEK\n");
        Set<String> keySet = factories.keySet();
        for (String key : keySet) {
            Set<String> values = factories.get(key);
            if (values == null || values.isEmpty()) {
                continue;
            }
            writer.write(key);
            writer.write("=\\\n  ");
            StringJoiner joiner = new StringJoiner(",\\\n  ");
            for (String value : values) {
                joiner.add(value);
            }
            writer.write(joiner.toString());
            writer.newLine();
        }
        writer.flush();
    }


}
