package cd.casic.plugin;

import cd.casic.plugin.utils.FrontResourceUtils;
import cn.hutool.core.io.IoUtil;
import cn.hutool.crypto.digest.DigestUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.pf4j.PluginWrapper;
import org.pf4j.RuntimeMode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 前端资源处理器，将各个插件的css和js资源合并
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class FrontResourceProcessor {

    @Autowired
    private PluginManager pluginManager;

    public List<DataBuffer> uglifyJsBundle() {
        List<DataBuffer> dataBuffers = new ArrayList<>();
        List<PluginWrapper> startedPlugins = pluginManager.getStartedPlugins();
        String plugins = String.format("this.enabledPluginNames = [%s];",
                startedPlugins.stream()
                        .map(PluginWrapper::getPluginId)
                        .collect(Collectors.joining("','", "'", "'")));

        for (PluginWrapper pluginWrapper : startedPlugins) {
            String pluginName = pluginWrapper.getPluginId();
            Resource jsBundleResource = FrontResourceUtils.getJsBundleResource(pluginManager, pluginName,
                    FrontResourceUtils.JS_BUNDLE);

            if (jsBundleResource != null) {
                try (InputStream inputStream = jsBundleResource.getInputStream()) {
                    byte[] bytes = IoUtil.readBytes(inputStream);
                    DataBuffer dataBuffer = DefaultDataBufferFactory.sharedInstance.wrap(bytes);
                    dataBuffers.add(dataBuffer);
                    // Add a new line after each plugin bundle to avoid syntax error
                    byte[] newLineBytes = "\n".getBytes(StandardCharsets.UTF_8);
                    dataBuffers.add(DefaultDataBufferFactory.sharedInstance.wrap(newLineBytes));
                } catch (IOException e) {
                    log.error("Failed to read plugin bundle resource", e);
                }
            }
        }

        // Add the plugins JavaScript object at the end
        byte[] pluginsBytes = plugins.getBytes(StandardCharsets.UTF_8);
        DataBuffer pluginsDataBuffer = DefaultDataBufferFactory.sharedInstance.wrap(pluginsBytes);
        dataBuffers.add(pluginsDataBuffer);


        return dataBuffers;
    }

    public List<DataBuffer> uglifyCssBundle() {
        List<DataBuffer> cssDataBuffers = new ArrayList<>();
        for (PluginWrapper pluginWrapper : pluginManager.getStartedPlugins()) {
            String pluginName = pluginWrapper.getPluginId();
            Resource resource = FrontResourceUtils.getJsBundleResource(pluginManager, pluginName, FrontResourceUtils.CSS_BUNDLE);

            if (resource != null) {
                try (InputStream inputStream = resource.getInputStream()) {
                    byte[] cssBytes = IoUtil.readBytes(inputStream); // Assuming you have Apache Commons IO for this

                    DataBuffer dataBuffer = new DefaultDataBufferFactory().wrap(cssBytes);
                    cssDataBuffers.add(dataBuffer);
                } catch (IOException e) {
                    log.error("Failed to read plugin css bundle resource for plugin: {}", pluginName, e);
                }
            }
        }

        return cssDataBuffers;
    }

    public String generateJsBundleVersion() {
        if (RuntimeMode.DEVELOPMENT.equals(pluginManager.getRuntimeMode())) {
            return String.valueOf(System.currentTimeMillis());
        }
        var compactVersion = pluginManager.getStartedPlugins()
                .stream()
                .sorted(Comparator.comparing(PluginWrapper::getPluginId))
                .map(pluginWrapper -> pluginWrapper.getPluginId() + ":"
                        + pluginWrapper.getDescriptor().getVersion()
                )
                .collect(Collectors.joining());

        return DigestUtil.sha256Hex(compactVersion);
    }
}
