package cn.cordys.common.utils;


import cn.cordys.common.constants.InternalUserView;
import cn.cordys.common.dto.BaseTreeNode;
import cn.cordys.common.dto.ChartAnalysisDbRequest;
import cn.cordys.common.dto.ChartAnalysisRequest;
import cn.cordys.common.dto.chart.ChartCategoryAxisDbParam;
import cn.cordys.common.dto.chart.ChartValueAxisDbParam;
import cn.cordys.common.dto.condition.BaseCondition;
import cn.cordys.common.dto.condition.CombineSearch;
import cn.cordys.common.dto.condition.FilterCondition;
import cn.cordys.common.dto.condition.FilterDBCondition;
import cn.cordys.common.exception.GenericException;
import cn.cordys.common.service.BaseResourceFieldService;
import cn.cordys.common.uid.utils.EnumUtils;
import cn.cordys.common.util.*;
import cn.cordys.context.OrganizationContext;
import cn.cordys.crm.system.constants.FieldSourceType;
import cn.cordys.crm.system.constants.FieldType;
import cn.cordys.crm.system.dto.field.DatasourceField;
import cn.cordys.crm.system.dto.field.DepartmentField;
import cn.cordys.crm.system.dto.field.base.BaseField;
import cn.cordys.crm.system.dto.response.ModuleFormConfigDTO;
import cn.cordys.crm.system.mapper.ExtAttachmentMapper;
import cn.cordys.crm.system.service.DepartmentService;
import cn.cordys.crm.system.service.ModuleFormCacheService;
import cn.cordys.crm.system.service.UserViewService;
import cn.cordys.security.SessionUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

import static cn.cordys.common.utils.IndustryUtils.getIndustries;

/**
 * @Author: jianxing
 * @CreateTime: 2025-07-28  17:31
 * 拦截高级搜索等查询
 * 处理高级搜索等通用查询条件
 * 1. 处理视图查询条件
 * 2. 预先过滤不合法的查询条件
 * 3. 处理成员选项中的 CURRENT_USER
 */
@Aspect
@Component
public class ConditionFilterUtils {

    private static final String COUNT_FIELD = "COUNT";

    public static ChartAnalysisDbRequest parseChartAnalysisRequest(ChartAnalysisRequest request, ModuleFormConfigDTO formConfig) {
        List<BaseField> fields = formConfig.getFields();

        BaseField departmentField = new DepartmentField();
        departmentField.setId("departmentId");
        departmentField.setType(FieldType.DEPARTMENT.name());
        departmentField.setBusinessKey("departmentId");
        fields.add(departmentField);

        ChartAnalysisDbRequest chartAnalysisDbRequest = BeanUtils.copyBean(new ChartAnalysisDbRequest(), request);
        chartAnalysisDbRequest.setCategoryAxisParam(BeanUtils.copyBean(new ChartCategoryAxisDbParam(), request.getChartConfig().getCategoryAxis()));
        if (request.getChartConfig().getSubCategoryAxis() != null) {
            chartAnalysisDbRequest.setSubCategoryAxisParam(BeanUtils.copyBean(new ChartCategoryAxisDbParam(), request.getChartConfig().getSubCategoryAxis()));
        }
        chartAnalysisDbRequest.setValueAxisParam(BeanUtils.copyBean(new ChartValueAxisDbParam(), request.getChartConfig().getValueAxis()));

        // 处理视图查询条件
        chartAnalysisDbRequest.setViewFilterCondition(getViewCondition(chartAnalysisDbRequest.getViewId()));

        replaceDBCondition(fields, chartAnalysisDbRequest.getFilterCondition());
        replaceDBCondition(fields, chartAnalysisDbRequest.getViewFilterCondition());

        // 处理高级搜索条件
        parseCondition(chartAnalysisDbRequest.getFilterCondition());
        // 处理视图筛选条件
        parseCondition(chartAnalysisDbRequest.getViewFilterCondition());

        ChartCategoryAxisDbParam xAxisParam = chartAnalysisDbRequest.getCategoryAxisParam();
        ChartCategoryAxisDbParam subXAxisParam = chartAnalysisDbRequest.getSubCategoryAxisParam();
        ChartValueAxisDbParam yAxisParam = chartAnalysisDbRequest.getValueAxisParam();

        BaseField xBaseField = getBaseFieldWithCheck(fields, xAxisParam.getFieldId());
        BaseField yBaseField = getBaseFieldWithCheck(fields, yAxisParam.getFieldId());

        xAxisParam.setBlob(xBaseField.isBlob());
        xAxisParam.setBusinessField(StringUtils.isNotBlank(xBaseField.getBusinessKey()));
        xAxisParam.setBusinessFieldName(CaseFormatUtils.camelToUnderscore(xBaseField.getBusinessKey()));

        if (yBaseField != null) {
            yAxisParam.setBlob(yBaseField.isBlob());
            yAxisParam.setBusinessField(StringUtils.isNotBlank(yBaseField.getBusinessKey()));
            yAxisParam.setBusinessFieldName(CaseFormatUtils.camelToUnderscore(yBaseField.getBusinessKey()));
        }

        if (subXAxisParam != null) {
            BaseField subXBaseField = getBaseFieldWithCheck(fields, subXAxisParam.getFieldId());
            subXAxisParam.setBlob(subXBaseField.isBlob());
            subXAxisParam.setBusinessField(StringUtils.isNotBlank(subXBaseField.getBusinessKey()));
            subXAxisParam.setBusinessFieldName(CaseFormatUtils.camelToUnderscore(subXBaseField.getBusinessKey()));
        }

        return chartAnalysisDbRequest;
    }

    private static BaseField getBaseFieldWithCheck(List<BaseField> fields, String fieldKey) {
        if (StringUtils.isBlank(fieldKey)) {
            return null;
        }
        if (Strings.CS.equals(fieldKey, COUNT_FIELD)) {
            return null;
        }
        return fields.stream()
                .filter(field -> Strings.CI.equals(field.getId(), fieldKey)
                        || Strings.CI.equals(field.getBusinessKey(), fieldKey))
                .findFirst().orElseThrow(() -> new GenericException(Translator.get("module.field.not_exist")));
    }

    public static void parseCondition(BaseCondition baseCondition) {
        parseCondition(baseCondition, null);
    }

    public static void parseCondition(BaseCondition baseCondition, String formKey) {
        ModuleFormCacheService moduleFormCacheService = CommonBeanFactory.getBean(ModuleFormCacheService.class);
        ModuleFormConfigDTO businessFormConfig = Objects.requireNonNull(moduleFormCacheService).getBusinessFormConfig(formKey, OrganizationContext.getOrganizationId());
        List<BaseField> fields = businessFormConfig.getFields();

        // 处理视图查询条件
        baseCondition.setViewCombineSearch(getViewCondition(baseCondition.getViewId()));

        CombineSearch combineSearch = baseCondition.getCombineSearch();
        CombineSearch viewCombineSearch = baseCondition.getViewCombineSearch();

        replaceFilterDBCondition(fields, baseCondition);
        replaceDBCondition(fields, combineSearch);
        replaceDBCondition(fields, viewCombineSearch);

        // 处理高级搜索条件
        parseCondition(combineSearch);
        // 处理视图筛选条件
        parseCondition(viewCombineSearch);
    }

    /**
     * 将 FilterCondition 替换成 FilterDBCondition，并设置数据库查询相关属性
     *
     * @param fields
     * @param combineSearch
     */
    private static void replaceDBCondition(List<BaseField> fields, CombineSearch combineSearch) {
        if (combineSearch == null || CollectionUtils.isEmpty(combineSearch.getConditions())) {
            return;
        }
        List<FilterCondition> conditions = combineSearch.getConditions();
        replaceDBConditions(fields, conditions);
        // 重新设置conditions
        combineSearch.setConditions(conditions);
    }

    private static void replaceFilterDBCondition(List<BaseField> fields, BaseCondition baseCondition) {
        if (baseCondition == null || CollectionUtils.isEmpty(baseCondition.getFilters())) {
            return;
        }
        List<FilterCondition> conditions = baseCondition.getFilters();
        replaceDBConditions(fields, conditions);
        // 重新设置 filters
        baseCondition.setFilters(conditions);
    }

    private static void replaceDBConditions(List<BaseField> fields, List<FilterCondition> conditions) {
        Map<String, BaseField> fieldMap = fields.stream()
                .collect(Collectors.toMap(BaseField::getId, field -> field));

        for (int i = 0; i < conditions.size(); i++) {
            FilterCondition condition = conditions.get(i);
            // 将 FilterCondition 替换成 FilterDBCondition
            FilterDBCondition dbCondition = BeanUtils.copyBean(new FilterDBCondition(), condition);
            conditions.set(i, dbCondition);

            BaseField baseField = fieldMap.get(condition.getName());
            if (baseField != null) {
                dbCondition.setBlob(baseField.isBlob());
                dbCondition.setMultipleValue(baseField.multiple());
                if (StringUtils.isBlank(baseField.getResourceFieldId())) {
                    // 处理表单字段
                    parseFilterDBCondition(dbCondition, baseField);
                } else {
                    // 处理显示字段
                    BaseField refResourceField = fieldMap.get(baseField.getResourceFieldId());
                    if (refResourceField instanceof DatasourceField datasourceField) {
                        parseFilterDBCondition(dbCondition, baseField);
                        if (baseField.hasBusinessKey()) {
                            // 暂时只处理显示字段
                            dbCondition.setName(CaseFormatUtils.camelToUnderscore(baseField.getBusinessKey()));
                        } else {
                            String actualFieldId = baseField.getId().replace((baseField.getResourceFieldId() + BaseResourceFieldService.REF_UNDERLINE), StringUtils.EMPTY);
                            dbCondition.setName(actualFieldId);
                        }
                        dbCondition.setRefFiled(true);

                        dbCondition.setRefMainFieldName(refResourceField.idOrBusinessKey());
                        if (refResourceField.hasBusinessKey()) {
                            dbCondition.setRefMainFieldName(CaseFormatUtils.camelToUnderscore(refResourceField.getBusinessKey()));
                        } else {
                            dbCondition.setRefMainFieldName(refResourceField.getId());
                        }
                        dbCondition.setRefMainCustomField(!refResourceField.hasBusinessKey());

                        FieldSourceType fieldSourceType = FieldSourceType.safeValueOf(datasourceField.getDataSourceType());
                        if (fieldSourceType != null) {
                            dbCondition.setRefMainTableName(fieldSourceType.getTableName());
                        } else {
                            dbCondition.setRefMainTableName(FieldSourceType.CUSTOM_FORM.getTableName());
                        }
                    }
                }
            }
        }
    }

    private static void parseFilterDBCondition(FilterDBCondition dbCondition, BaseField baseField) {
        dbCondition.setName(baseField.idOrBusinessKey());
        dbCondition.setCustomField(!baseField.hasBusinessKey());
        dbCondition.setMultipleValue(baseField.multiple());
    }

    private static void parseCondition(CombineSearch combineSearch) {
        if (combineSearch == null) {
            return;
        }

        List<FilterCondition> validConditions = getValidConditions(combineSearch.getConditions());
        validConditions.forEach(item -> {
            Object combineValue = item.getCombineValue();
            String combineOperator = item.getCombineOperator();
            item.setValue(combineValue);
            item.setOperator(combineOperator);
            if (item.getValue() != null && item.getCombineValue() instanceof String strValue
                    && Strings.CS.equalsAny(item.getCombineOperator(), FilterCondition.CombineConditionOperator.CONTAINS.name(),
                    FilterCondition.CombineConditionOperator.NOT_CONTAINS.name())) {
                // 转义 mysql 的特殊字符
                item.setValue(BaseCondition.transferKeyword(strValue));
            }

            if (item.getValue() != null && Strings.CS.contains(item.getType(), "MULTIPLE")
                    && Strings.CS.equalsAny(item.getCombineOperator(), FilterCondition.CombineConditionOperator.EQUALS.name(),
                    FilterCondition.CombineConditionOperator.NOT_EQUALS.name())) {
                // 转义 mysql 的特殊字符
                item.setValue(JSON.toJSONString(item.getCombineValue()));
            }

            if (item.getValue() != null && Strings.CS.equals(item.getType(), FieldType.ATTACHMENT.name())) {
                // 附件类型转义名称
                List<String> attachmentNames = List.of(item.getCombineValue().toString().split(StringUtils.SPACE));
                ExtAttachmentMapper attachmentMapper = CommonBeanFactory.getBean(ExtAttachmentMapper.class);
                List<String> attachmentIds = Objects.requireNonNull(attachmentMapper).getAttachmentIdsByNames(attachmentNames);
                item.setValue(CollectionUtils.isEmpty(attachmentIds) ? attachmentNames : attachmentIds);
            }


            if (item.getValue() != null && Strings.CS.equals(item.getType(), FieldType.INDUSTRY.name())) {
                String str = item.getValue().toString()
                        .replace("[", "")
                        .replace("]", "");

                List<String> list = Arrays.stream(str.split(","))
                        .map(String::trim)
                        .collect(Collectors.toList());
                List<String> values = IndustryUtils.getValues(getIndustries(), list);
                values.addAll(list);
                item.setValue(values.stream().distinct().toList());
            }
        });
        replaceCurrentUser(validConditions);
        combineSearch.setConditions(validConditions);
    }

    private static CombineSearch getViewCondition(String viewId) {
        if (StringUtils.isNotBlank(viewId) && !InternalUserView.isInternalUserView(viewId)) {
            // 查询视图
            UserViewService userViewService = CommonBeanFactory.getBean(UserViewService.class);
            String viewSearchMode = Objects.requireNonNull(userViewService).getSearchMode(viewId);
            List<FilterCondition> viewConditions = userViewService.getFilterConditions(viewId);

            //新增子节点数据
            List<BaseTreeNode> tree = Objects.requireNonNull(CommonBeanFactory.getBean(DepartmentService.class)).getTree(OrganizationContext.getOrganizationId());
            buildConditions(viewConditions, tree);

            CombineSearch viewCondition = new CombineSearch();
            viewCondition.setSearchMode(viewSearchMode);
            viewCondition.setConditions(viewConditions);
            return viewCondition;
        }
        return null;
    }


    /**
     * 包含新增子节点数据
     *
     * @param conditions
     */
    private static void buildConditions(List<FilterCondition> conditions, List<BaseTreeNode> tree) {
        if (CollectionUtils.isNotEmpty(conditions)) {
            conditions.forEach(condition -> {
                if (CollectionUtils.isNotEmpty(condition.getContainChildIds())) {
                    condition.getContainChildIds().forEach(id -> {
                        List<String> ids = getIds(tree, id);
                        ids.addAll(condition.getContainChildIds());
                        condition.setValue(ids.stream().distinct().toList());
                    });
                }
            });
        }
    }


    public static List<String> getIds(List<BaseTreeNode> tree, String targetId) {
        List<String> ids = new ArrayList<>();
        for (BaseTreeNode node : tree) {
            BaseTreeNode targetNode = findNode(node, targetId);
            if (targetNode != null) {
                collectIds(targetNode, ids);
                break;
            }
        }
        return ids;
    }

    private static BaseTreeNode findNode(BaseTreeNode node, String targetId) {
        if (node.getId().equals(targetId)) {
            return node;
        }
        for (BaseTreeNode child : node.getChildren()) {
            BaseTreeNode result = findNode(child, targetId);
            if (result != null) {
                return result;
            }
        }
        return null;
    }

    private static void collectIds(BaseTreeNode node, List<String> ids) {
        ids.add(node.getId());
        for (BaseTreeNode child : node.getChildren()) {
            collectIds(child, ids);
        }
    }

    /**
     * 处理成员选项中的 CURRENT_USER
     * 替换当前用户的用户ID
     *
     * @param validConditions
     */
    private static void replaceCurrentUser(List<FilterCondition> validConditions) {
        for (FilterCondition validCondition : validConditions) {
            Object value = validCondition.getCombineValue();
            if (value instanceof List arrayValues) {
                for (int i = 0; i < arrayValues.size(); i++) {
                    Object arrayValue = arrayValues.get(i);
                    if (arrayValue != null && Strings.CS.equals(arrayValue.toString(), InternalUserView.CURRENT_USER)) {
                        // 替换当前用户的用户ID
                        arrayValues.set(i, SessionUtils.getUserId());
                    }
                }
            }
        }
    }

    public static List<FilterCondition> getValidConditions(List<FilterCondition> conditions) {
        if (CollectionUtils.isEmpty(conditions)) {
            return List.of();
        }
        return conditions.stream().filter(FilterCondition::valid).collect(Collectors.toList());
    }
}
