package cd.casic.server.system.plugin.example.web;

import cd.casic.plugin.PluginDescriptorStorage;
import cd.casic.plugin.PluginManager;
import cd.casic.plugin.PluginProperties;
import cd.casic.plugin.utils.SM4EncryptUtil;
import cd.casic.server.system.plugin.example.web.service.impl.PluginStorageServiceImpl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.pf4j.PluginState;
import org.pf4j.PluginWrapper;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @Author：mianbin
 * @Package：cd.casic.opsmodulepluginsexampleweb.controller
 * @Project：ops
 * @name：PluginManagerControoler
 * @Date：2024/03/20 15:05
 * @Filename：PluginManagerControoler
 * @description：Todo
 */
@RestController
@RequestMapping("/plugin")
@Slf4j
public class PluginManagerController {
    @Resource
    private PluginProperties pluginProperties;
    @Resource
    private PluginStorageServiceImpl pluginStorageService;

    @Resource
    private PluginManager pluginManager;

    @PostMapping("upload")
    public boolean uploadPlugin(@RequestParam("file") MultipartFile file) throws IOException {
        InputStream is = file.getInputStream();
        Files.copy(is, Paths.get(pluginProperties.getPluginsRoot()).resolve(Objects.requireNonNull(file.getOriginalFilename())));
        is.close();
        return true;
    }

    @GetMapping("reload")
    public void reloadPlugins() {
        pluginManager.unloadPlugins();
        pluginManager.loadPlugins();
    }

    @GetMapping("load")
    public String loadPlugin(@RequestParam() String pluginId) {
        PluginWrapper plugin = pluginManager.getPlugin(pluginId);
        if (plugin != null) {
            return pluginManager.loadPlugin(plugin.getPluginPath());
        } else {
            return "Plugin not found";
        }
    }

    @GetMapping("unload")
    public boolean unloadPlugin(@RequestParam() String pluginId) {
        return pluginManager.unloadPlugin(pluginId);
    }

    @GetMapping("start")
    public PluginState startPlugin(@RequestParam() String pluginId) {
        return pluginManager.startPlugin(pluginId);
    }

    @GetMapping("stop")
    public PluginState stopPlugin(@RequestParam() String pluginId) {
        return pluginManager.stopPlugin(pluginId);
    }

    @GetMapping("disable")
    public boolean disablePlugin(@RequestParam() String pluginId) {
        this.setPluginDisable(pluginId);
        return pluginManager.disablePlugin(pluginId);
    }

    @GetMapping("enable")
    public boolean enablePlugin(@RequestParam() String pluginId) {
        this.setPluginEnable(pluginId);
        return pluginManager.enablePlugin(pluginId);
    }

    @GetMapping("delete")
    public boolean deletePlugin(@RequestParam() String pluginId) {
        return pluginManager.deletePlugin(pluginId);
    }

    @GetMapping("lists")
    public List<JSONObject> listPlugin() {
        return getPlugins();
    }


    @GetMapping("list")
    public JSONArray extensions(@RequestParam String extensionClass) throws ClassNotFoundException {
        List extensions = pluginManager.getExtensions(Class.forName(extensionClass));
        JSONArray result = new JSONArray();
        for (Object extension : extensions) {
            if (extension instanceof OperationButtonExtension) {
                PluginWrapper plugin = pluginManager.whichPlugin(extension.getClass());
                result.add(new JSONObject().fluentPut("class", extension.getClass().getName())
                        .fluentPut("name", ((OperationButtonExtension) extension).name()).fluentPut("plugin", new JSONObject()
                                .fluentPut("id", plugin.getPluginId())
                                .fluentPut("version", plugin.getDescriptor().getVersion())
                                .fluentPut("path", plugin.getPluginPath().toString())
                                .fluentPut("state", plugin.getPluginState())
                                .fluentPut("class", plugin.getDescriptor().getPluginClass())));
            }
        }
        return result;
    }

    @GetMapping("click")
    public String click(@RequestParam String extensionClass, @RequestParam String name) throws ClassNotFoundException {
        List extensions = pluginManager.getExtensions(Class.forName(extensionClass));
        for (Object extension : extensions) {
            if (extension instanceof OperationButtonExtension && ((OperationButtonExtension) extension).name().equals(name)) {
                return ((OperationButtonExtension) extension).onClick();
            }
        }
        return "Extension not found or unavailable";
    }

    private List<JSONObject> getPlugins() {
        ArrayList<JSONObject> list = new ArrayList<>();
        List<PluginDescriptorStorage> pluginDescriptors = pluginStorageService.list();
        for (PluginDescriptorStorage pluginDescriptor : pluginDescriptors){
            // 校验license
            if (SM4EncryptUtil.checkLicense(pluginDescriptor.getLicense(), pluginDescriptor.getPluginId())){
                list.add(new JSONObject()
                        .fluentPut("id", pluginDescriptor.getPluginId())
                        .fluentPut("version", pluginDescriptor.getVersion())
                        .fluentPut("path", pluginDescriptor.getPluginDirPath())
                        .fluentPut("state", pluginManager.getPlugin(pluginDescriptor.getPluginId()).getPluginState())
                        .fluentPut("class", pluginDescriptor.getPluginClass())
                );
            }
        }
        return list;
    }
    private void setPluginEnable(String pluginId) {
        PluginWrapper plugin = pluginManager.getPlugin(pluginId);
        PluginDescriptorStorage descriptorStorage = pluginStorageService.convert(plugin);
        descriptorStorage.setEnable(1); // 1 是启用
        pluginStorageService.updateById(descriptorStorage);
    }

    private void setPluginDisable(String pluginId) {
        PluginWrapper plugin = pluginManager.getPlugin(pluginId);
        PluginDescriptorStorage descriptorStorage = pluginStorageService.convert(plugin);
        descriptorStorage.setEnable(0); // 0 是禁用
        pluginStorageService.updateById(descriptorStorage);
    }
}
