package tech.easyflow.ai.node;

import com.easyagents.core.util.StringUtil;
import com.easyagents.flow.core.chain.Chain;
import com.easyagents.flow.core.chain.Parameter;
import com.easyagents.flow.core.node.BaseNode;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.tenant.TenantManager;
import tech.easyflow.common.util.SpringContextUtil;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.datacenter.execution.model.DatacenterSqlQueryRequest;
import tech.easyflow.datacenter.execution.model.DatasetRef;
import tech.easyflow.datacenter.execution.service.DatacenterDatasetQueryService;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SearchDatasetNode extends BaseNode {

    private static final Pattern PARAM_PATTERN = Pattern.compile("\\{\\{(.+?)\\}\\}");

    private DatasetRef datasetRef;
    private String querySql;

    public SearchDatasetNode() {
    }

    public SearchDatasetNode(DatasetRef datasetRef) {
        this.datasetRef = datasetRef;
    }

    public SearchDatasetNode(DatasetRef datasetRef, String querySql) {
        this.datasetRef = datasetRef;
        this.querySql = querySql;
    }

    @Override
    public Map<String, Object> execute(Chain chain) {
        Map<String, Object> params = chain.getState().resolveParameters(this);
        DatacenterDatasetQueryService queryService = SpringContextUtil.getBean(DatacenterDatasetQueryService.class);
        DatacenterSqlQueryRequest request = buildRuntimeRequest(params);
        Map<String, Object> result = new HashMap<>();
        try {
            TenantManager.ignoreTenantCondition();
            List<Row> rows = queryService.queryBySql(request);
            result.put(resolveOutputKey("data"), rows);
            return result;
        } finally {
            TenantManager.restoreTenantCondition();
        }
    }

    private DatacenterSqlQueryRequest buildRuntimeRequest(Map<String, Object> params) {
        DatacenterSqlQueryRequest request = new DatacenterSqlQueryRequest();
        request.setDatasetRef(copyDatasetRef());
        request.setSql(resolveQuerySql(params));
        return request;
    }

    private String resolveQuerySql(Map<String, Object> params) {
        String sql = resolveTemplateString(querySql, params);
        if (!StringUtil.hasText(sql)) {
            throw new BusinessException("查询数据节点未设置 SQL");
        }
        return sql.trim();
    }

    private DatasetRef copyDatasetRef() {
        DatasetRef copy = new DatasetRef();
        copy.setSourceId(datasetRef == null ? null : datasetRef.getSourceId());
        copy.setCatalogId(datasetRef == null ? null : datasetRef.getCatalogId());
        copy.setCatalogName(datasetRef == null ? null : datasetRef.getCatalogName());
        copy.setTableId(null);
        copy.setTableName(null);
        copy.setVersionId(null);
        return copy;
    }

    private String resolveTemplateString(String text, Map<String, Object> params) {
        if (!StringUtil.hasText(text) || params == null || params.isEmpty()) {
            return text;
        }
        Matcher matcher = PARAM_PATTERN.matcher(text);
        StringBuffer buffer = new StringBuffer();
        while (matcher.find()) {
            Object replacement = params.get(matcher.group(1));
            matcher.appendReplacement(buffer, replacement == null ? "" : Matcher.quoteReplacement(String.valueOf(replacement)));
        }
        matcher.appendTail(buffer);
        return buffer.toString();
    }

    private String resolveOutputKey(String defaultName) {
        List<Parameter> outputDefs = getOutputDefs();
        if (outputDefs == null || outputDefs.isEmpty()) {
            return defaultName;
        }
        String name = outputDefs.get(0).getName();
        return StringUtil.hasText(name) ? name : defaultName;
    }

    public DatasetRef getDatasetRef() {
        return datasetRef;
    }

    public void setDatasetRef(DatasetRef datasetRef) {
        this.datasetRef = datasetRef;
    }

    public String getQuerySql() {
        return querySql;
    }

    public void setQuerySql(String querySql) {
        this.querySql = querySql;
    }
}
