package tech.easyflow.ai.easyagents.tool;

import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.easyagents.core.model.chat.tool.BaseTool;
import com.easyagents.core.model.chat.tool.Parameter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mybatisflex.core.query.QueryWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tech.easyflow.ai.easyagents.CustomMultipartFile;
import tech.easyflow.ai.entity.Plugin;
import tech.easyflow.ai.entity.PluginItem;
import tech.easyflow.ai.mapper.PluginMapper;
import tech.easyflow.ai.service.PluginItemService;
import tech.easyflow.common.ai.plugin.NestedParamConverter;
import tech.easyflow.common.ai.plugin.PluginHttpClient;
import tech.easyflow.common.ai.plugin.PluginParam;
import tech.easyflow.common.ai.plugin.PluginParamConverter;
import tech.easyflow.common.filestorage.FileStorageManager;
import tech.easyflow.common.filestorage.FileStorageService;
import tech.easyflow.common.util.SpringContextUtil;

import java.io.*;
import java.lang.reflect.Array;
import java.math.BigInteger;
import java.util.*;

public class PluginTool extends BaseTool {

    // 插件工具id
    private BigInteger pluginToolId;
    private String name;
    private String description;
    private Parameter[] parameters;
    private static final Logger logger = LoggerFactory.getLogger(PluginTool.class);

    public PluginTool() {

    }

    public PluginTool(PluginItem pluginItem) {
        this.name = pluginItem.getEnglishName();
        this.description = pluginItem.getDescription();
        this.pluginToolId = pluginItem.getId();
        this.parameters = getDefaultParameters(pluginItem.getInputData());
    }

    public BigInteger getPluginToolId() {
        return pluginToolId;
    }

    public void setPluginToolId(BigInteger pluginToolId) {
        this.pluginToolId = pluginToolId;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public void setParameters(Parameter[] parameters) {
        this.parameters = parameters;
    }

    private Plugin getAiPlugin(BigInteger pluginId) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select("*")
                .from("tb_plugin")
                .where("id = ?", pluginId);
        PluginMapper pluginMapper = SpringContextUtil.getBean(PluginMapper.class);
        Plugin plugin1 = pluginMapper.selectOneByQuery(queryWrapper);
        return plugin1;
    }

    private Parameter[] getDefaultParameters(String inputData) {
        PluginItemService pluginToolService = SpringContextUtil.getBean(PluginItemService.class);
        QueryWrapper queryAiPluginToolWrapper = QueryWrapper.create()
                .select("*")
                .from("tb_plugin_item")
                .where("id = ? ", this.pluginToolId);
        PluginItem pluginItem = pluginToolService.getMapper().selectOneByQuery(queryAiPluginToolWrapper);
        List<Map<String, Object>> dataList = null;
        if (pluginItem == null || pluginItem.getInputData() == null){
            dataList = getDataList(inputData);
        } else {
            dataList = getDataList(pluginItem.getInputData());
        }
        Parameter[] params = new Parameter[dataList.size()];
        for (int i = 0; i < dataList.size(); i++) {
            Map<String, Object> item = dataList.get(i);
            Parameter parameter = new Parameter();
            parameter.setName((String) item.get("name"));
            parameter.setDescription((String) item.get("description"));
            parameter.setRequired((boolean) item.get("required"));
            String type = (String) item.get("type");
            if (type != null) {
                parameter.setType(type.toLowerCase());
            }
            params[i] = parameter;
        }
        return params;
    }

    // 转换输入参数
    private List<Map<String, Object>> getDataList(String jsonArray){
        List<Map<String, Object>> dataList;
        if (jsonArray == null) {
            return new ArrayList<>();
        }
        try {
            dataList = new ObjectMapper().readValue(
                    jsonArray,
                    new TypeReference<List<Map<String, Object>>>(){}
            );
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return dataList;
    }


    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public Parameter[] getParameters() {
        return parameters;
    }

    @Override
    public Object invoke(Map<String, Object> argsMap) {
     return runPluginTool(argsMap, null, this.pluginToolId);
    }

    public Object runPluginTool(Map<String, Object> argsMap, String inputData, BigInteger pluginId){
        PluginItemService pluginToolService = SpringContextUtil.getBean(PluginItemService.class);
        QueryWrapper queryAiPluginToolWrapper = QueryWrapper.create()
                .select("*")
                .from("tb_plugin_item")
                .where("id = ? ", pluginId);
        PluginItem pluginItem = pluginToolService.getMapper().selectOneByQuery(queryAiPluginToolWrapper);
        String method = pluginItem.getRequestMethod().toUpperCase();
        Plugin plugin = getAiPlugin(pluginItem.getPluginId());

        String url;
        if (!StrUtil.isEmpty(pluginItem.getBasePath())) {
            url = plugin.getBaseUrl()+ pluginItem.getBasePath();
        } else {
            url = plugin.getBaseUrl()+"/"+ pluginItem.getName();
        }

        List<Map<String, Object>> headers = getDataList(plugin.getHeaders());
        Map<String, Object> headersMap = new HashMap<>();
        for (Map<String, Object> header : headers) {
            headersMap.put((String) header.get("label"), header.get("value"));
        }
        List<PluginParam> params = new ArrayList<>();

        String authType = plugin.getAuthType();
        if (!StrUtil.isEmpty(authType) && "apiKey".equals(plugin.getAuthType())){
            if ("headers".equals(plugin.getPosition())){
                headersMap.put(plugin.getTokenKey(), plugin.getTokenValue());
            } else {
                PluginParam pluginParam = new PluginParam();
                pluginParam.setName(plugin.getTokenKey());
                pluginParam.setDefaultValue(plugin.getTokenValue());
                pluginParam.setEnabled(true);
                pluginParam.setRequired(true);
                pluginParam.setMethod("query");
                params.add(pluginParam);
            }
        }
        List<PluginParam> pluginParams = null;
        // 前端点击试运行传过来的参数
        if (inputData != null && !inputData.isEmpty()){
            pluginParams = PluginParamConverter.convertFromJson(inputData);
            // 大模型命中funcation_call 调用参数
        } else {
            pluginParams = PluginParamConverter.convertFromJson(pluginItem.getInputData());
        }

        // 准备存放不同位置的参数
        List<PluginParam> queryParams = new ArrayList<>();
        List<PluginParam> bodyParams = new ArrayList<>();
        List<PluginParam> headerParams = new ArrayList<>();
        List<PluginParam> pathParams = new ArrayList<>();
        Map<String, Object> nestedParams = NestedParamConverter.convertToNestedParamMap(pluginParams);

        // 遍历嵌套参数
        for (Map.Entry<String, Object> entry : nestedParams.entrySet()) {
            String paramName = entry.getKey();

            // 获取原始参数定义
            PluginParam originalParam = findOriginalParam(pluginParams, paramName);
            if (originalParam == null || !originalParam.isEnabled()) {
                continue;
            }

            // 创建参数副本以避免修改原始定义
            PluginParam requestParam = new PluginParam();
            requestParam.setName(originalParam.getName());
            requestParam.setDescription(originalParam.getDescription());
            requestParam.setRequired(originalParam.isRequired());

            requestParam.setEnabled(originalParam.isEnabled());
            requestParam.setMethod(originalParam.getMethod());
            requestParam.setChildren(originalParam.getChildren());
            // 优先级: argsMap值 < 参数默认值
            if (argsMap != null && argsMap.containsKey(paramName)) {
                // 1. 优先检查是否有有效的默认值
                if (hasValidDefaultValue(originalParam.getDefaultValue())) {
                    // 使用默认值
                    requestParam.setDefaultValue(originalParam.getDefaultValue());
                } else {
                    // 使用大模型返回的值
                    requestParam.setDefaultValue(argsMap.get(paramName));
                }
            } else if (hasValidDefaultValue(originalParam.getDefaultValue())) {
                // 2. 没有传参但默认值有效时使用默认值
                // 如果是文件类型
                if (originalParam.getType().equals("File")){
                    try {
                        FileStorageService fileStorageService = SpringContextUtil.getBean(FileStorageManager.class);
                        InputStream inputStream = fileStorageService.readStream((String)originalParam.getDefaultValue());
                        requestParam.setType("MultipartFile");
                        byte[] bytes = inputStreamToBytes(inputStream);
                        String contentType = FileTypeUtil.getType(new ByteArrayInputStream(bytes));
                        String fileUrl = (String) originalParam.getDefaultValue();
                        int lastSlashIndex = fileUrl.lastIndexOf("/");
                        String fileName = fileUrl.substring(lastSlashIndex + 1);
                        requestParam.setDefaultValue(new CustomMultipartFile(bytes, originalParam.getName(), fileName, contentType));
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                } else {
                    requestParam.setType(originalParam.getType());
                    requestParam.setDefaultValue(originalParam.getDefaultValue());
                }
            }
            // 根据method分类参数
            switch (originalParam.getMethod().toLowerCase()) {
                case "query":
                    queryParams.add(requestParam);
                    break;
                case "body":
                    bodyParams.add(requestParam);
                    break;
                case "header":
                    headerParams.add(requestParam);
                    break;
                case "path":
                    pathParams.add(requestParam);
                    break;
            }
        }

        // 合并所有参数
        List<PluginParam> allParams = new ArrayList<>();
        allParams.addAll(pathParams);
        allParams.addAll(queryParams);
        allParams.addAll(bodyParams);
        allParams.addAll(headerParams);
        allParams.addAll(params);

        // 发送请求
        JSONObject result = PluginHttpClient.sendRequest(url, method, headersMap, allParams);
        if (result.get("error") != null){
            logger.error("插件调用失败");
            logger.error(result.get("error").toString());
        }
        return result;
    }

    // 辅助方法：根据参数名查找原始参数定义
    private PluginParam findOriginalParam(List<PluginParam> params, String name) {
        for (PluginParam param : params) {
            if (name.equals(param.getName())) {
                return param;
            }
        }
        return null;
    }

    // 添加辅助方法判断默认值是否有效
    private boolean hasValidDefaultValue(Object defaultValue) {
        if (defaultValue == null) {
            return false;
        }

        // 字符串类型检查
        if (defaultValue instanceof CharSequence) {
            return !((CharSequence) defaultValue).toString().trim().isEmpty();
        }

        // 集合/数组类型检查
        if (defaultValue instanceof Collection) {
            return !((Collection<?>) defaultValue).isEmpty();
        }
        if (defaultValue instanceof Map) {
            return !((Map<?, ?>) defaultValue).isEmpty();
        }
        if (defaultValue.getClass().isArray()) {
            return Array.getLength(defaultValue) > 0;
        }

        // 其他类型直接认为有效
        return true;
    }

    private void processParamWithChildren(Map<String, Object> paramDef, Map<String, Object> argsMap, List<PluginParam> params) {
        boolean enabled = (boolean) paramDef.get("enabled");
        if (!enabled){
            return;
        }
        String paramName = (String) paramDef.get("name");
        PluginParam pluginParam = new PluginParam();
        pluginParam.setName(paramName);
        pluginParam.setDescription((String) paramDef.get("description"));
        pluginParam.setRequired((boolean) paramDef.get("required"));
        pluginParam.setType((String) paramDef.get("type"));
        pluginParam.setEnabled((boolean) paramDef.get("enabled"));
        pluginParam.setMethod((String) paramDef.get("method"));

        // 如果用户传了值，就用用户的值；否则用默认值
        if (paramDef.get("defaultValue") != null && !"".equals(paramDef.get("defaultValue"))) {
            pluginParam.setDefaultValue(paramDef.get("defaultValue"));
        } else if (argsMap != null && paramDef.get("name").equals(paramName) && paramDef.get("defaultValue") != null) {
            pluginParam.setDefaultValue(argsMap.get(paramName));
        }

        params.add(pluginParam);

        // 处理 children
        List<Map<String, Object>> children = (List<Map<String, Object>>) paramDef.get("children");
        if (children != null) {
            for (Map<String, Object> child : children) {
                processParamWithChildren(child, argsMap, params);
            }
        }
    }

    public static byte[] inputStreamToBytes(InputStream inputStream) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int nRead;
        byte[] data = new byte[1024]; // 1KB缓冲区

        while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, nRead);
        }

        buffer.flush();
        return buffer.toByteArray();
    }
}
